Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>OUT_OF_RANGE",
"Operand out of range, bitwise operation will lose information: {0}");
static final DiagnosticType SHIFT_AMOUNT_OUT_OF_BOUNDS = DiagnosticType.error(
"JSC_SHIFT_AMOUNT_OUT_OF_BOUNDS",
"Shift amount out of bounds: {0}");
static final DiagnosticType FRACTIONAL_BITWISE_OPERAND = DiagnosticType.error(
"JSC_FRACTIONAL_BITWISE_OPERAND",
"Fractional bitwise operand: {0}");
private static final double MAX_FOLD_NUMBER = Math.pow(2, 53);
@Override
Node optimizeSubtree(Node subtree) {
switch(subtree.getType()) {
case Token.CALL:
return tryFoldKnownMethods(subtree);
case Token.TYPEOF:
return tryFoldTypeof(subtree);
case Token.NOT:
case Token.NEG:
case Token.BITNOT:
return tryFoldUnaryOperator(subtree);
default:
return tryFoldBinaryOperator(subtree);
}
}
private Node tryFoldBinaryOperator(Node subtree) {
Node left = subtree.getFirstChild();
if (left == null) {
return subtree;
}
Node right = left.getNext();
if (right == null) {
return subtree;
}
// If we've reached here, node is truly a binary operator.
switch(subtree.getType()) {
case Token.GETPROP:
return tryFoldGetProp(subtree, left, right);
case Token.GETELEM:
return tryFoldGetElem(subtree, left, right);
case Token.INSTANCEOF:
return tryFoldInstanceof(subtree, left, right);
case Token.AND:
case Token.OR:
return tryFoldAndOr(subtree, left, right);
case Token.BITAND:
case Token.BITOR:
return tryFoldBitAndOr(subtree, left, right);
case Token.LSH:
case Token.RSH:
case Token.URSH:
return tryFoldShift(subtree, left, right);
case Token.ASSIGN:
return tryFoldAssign(subtree, left, right);
case Token.ADD:
return tryFoldAdd(subtree, left, right
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
*/
@SuppressWarnings("fallthrough")
private Node tryFoldComparison(Node n, Node left, Node right) {
if (!NodeUtil.isLiteralValue(left) || !NodeUtil.isLiteralValue(right)) {
// We only handle non-literal operands for LT and GT.
if (n.getType() != Token.GT && n.getType() != Token.LT) {
return n;
}
}
int op = n.getType();
boolean result;
// TODO(johnlenz): Use the JSType to compare nodes of different types.
boolean rightLiteral = NodeUtil.isLiteralValue(right);
boolean undefinedRight = ((Token.NAME == right.getType()
&& right.getString().equals("undefined"))
|| (Token.VOID == right.getType()
&& NodeUtil.isLiteralValue(right.getFirstChild())));
switch (left.getType()) {
case Token.VOID:
if (!NodeUtil.isLiteralValue(left.getFirstChild())) {
return n;
} else if (!rightLiteral) {
return n;
} else {
boolean nullRight = (Token.NULL == right.getType());
boolean equivalent = undefinedRight || nullRight;
switch (op) {
case Token.EQ:
// undefined is only equal to
result = equivalent;
break;
case Token.NE:
result = !equivalent;
break;
case Token.SHEQ:
result = undefinedRight;
break;
case Token.SHNE:
result = !undefinedRight;
break;
case Token.LT:
case Token.GT:
case Token.LE:
case Token.GE:
result = false;
break;
default:
return n;
}
}
break;
case Token.NULL:
if (undefinedRight) {
result = (op == Token.EQ);
break;
}
// fall through
case Token.TRUE:
case Token.FALSE:
if (undefinedRight) {
result = false;
break;
}
// fall through
case Token.THIS:
int tt = right.getType();
if (tt != Token.THIS &&
tt != Token.TRUE &&
tt != Token.FALSE &&
tt != Token.NULL) {
return n;
}
switch (op) {
case
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Id_export = Token.EXPORT,
Id_false = Token.FALSE,
Id_for = Token.FOR,
Id_function = Token.FUNCTION,
Id_if = Token.IF,
Id_in = Token.IN,
Id_new = Token.NEW,
Id_null = Token.NULL,
Id_return = Token.RETURN,
Id_switch = Token.SWITCH,
Id_this = Token.THIS,
Id_true = Token.TRUE,
Id_typeof = Token.TYPEOF,
Id_var = Token.VAR,
Id_void = Token.VOID,
Id_while = Token.WHILE,
Id_with = Token.WITH,
// the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c
Id_abstract = Token.RESERVED,
Id_boolean = Token.RESERVED,
Id_byte = Token.RESERVED,
Id_catch = Token.CATCH,
Id_char = Token.RESERVED,
Id_class = Token.RESERVED,
Id_const = Token.CONST,
Id_debugger = Token.DEBUGGER,
Id_double = Token.RESERVED,
Id_enum = Token.RESERVED,
Id_extends = Token.RESERVED,
Id_final = Token.RESERVED,
Id_finally = Token.FINALLY,
Id_float = Token.RESERVED,
Id_goto = Token.RESERVED,
Id_implements = Token.RESERVED,
Id_import = Token.IMPORT,
Id_instanceof = Token.INSTANCEOF,
Id_int = Token.RESERVED,
Id_interface = Token.RESERVED,
Id_long = Token.RESERVED,
Id_native = Token.RESERVED,
Id_package = Token.RESERVED,
Id_private = Token.RESERVED,
Id_protected = Token.RESERVED,
Id_public = Token.RESERVED,
Id_short = Token.RESERVED,
Id_static = Token.RESERVED,
Id_super = Token.RESERVED,
Id_synchronized = Token.RESERVED,
Id_throw = Token.THROW,
Id_
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> or in case this SourceFile came
// from a Jar, it could be the path to the Jar.
private String originalPath = null;
// Remember the offset for the previous line query. If the next line
// is after this point, we can start scanning at the previous offset rather
// than starting at the beginning of the file.
private int lastOffset;
private int lastLine;
private String code = null;
/**
* Construct a new abstract source file.
*
* @param fileName The file name of the source file. It does not necessarily
* need to correspond to a real path. But it should be unique. Will
* appear in warning messages emitted by the compiler.
*/
SourceFile(String fileName) {
this.fileName = fileName;
// Starting point: offset 0 is at line 1.
this.lastOffset = 0;
this.lastLine = 1;
}
//////////////////////////////////////////////////////////////////////////////
// Implementation
/**
* Gets all the code in this source file.
* @throws IOException
*/
public String getCode() throws IOException {
return code;
}
/**
* Gets a reader for the code in this source file.
*/
public Reader getCodeReader() throws IOException {
return new StringReader(getCode());
}
@VisibleForTesting
String getCodeNoCache() {
return code;
}
private void setCode(String sourceCode) {
code = sourceCode;
}
public String getOriginalPath() {
return originalPath != null ? originalPath : fileName;
}
public void setOriginalPath(String originalPath) {
this.originalPath = originalPath;
}
// For SourceFile types which cache source code that can be regenerated
// easily, flush the cache. We maintain the cache mostly to speed up
// generating source when displaying error messages, so dumping the file
// contents after the compile is a fine thing to do.
public void clearCachedSource() {
// By default, do nothing. Not all kinds of SourceFiles can regenerate
// code.
}
boolean hasSourceInMemory() {
return code != null;
}
/** Returns a unique name for the source file. */
public String getName() {
return fileName;
}
/**
* Gets the source line for the indicated line number.
*
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> * @param lineNumber the line number, 1 being the first line of the file.
* @return The line indicated. Does not include the newline at the end
* of the file. Returns {@code null} if it does not exist,
* or if there was an IO exception.
*/
public String getLine(int lineNumber) {
String js = "";
try {
// NOTE(nicksantos): Right now, this is optimized for few warnings.
// This is probably the right trade-off, but will be slow if there
// are lots of warnings in one file.
js = getCode();
} catch (IOException e) {
return null;
}
int pos = 0;
int startLine = 1;
// If we've saved a previous offset and it's for a line less than the
// one we're searching for, then start at that point.
if (lineNumber >= lastLine) {
pos = lastOffset;
startLine = lastLine;
}
for (int n = startLine; n < lineNumber; n++) {
int nextpos = js.indexOf('\n', pos);
if (nextpos == -1) {
return null;
}
pos = nextpos + 1;
}
// Remember this offset for the next search we do.
lastOffset = pos;
lastLine = lineNumber;
return (js.indexOf('\n', pos) == -1) ? null :
js.substring(pos, js.indexOf('\n', pos));
}
/**
* Get a region around the indicated line number. The exact definition of a
* region is implementation specific, but it must contain the line indicated
* by the line number. A region must not start or end by a carriage return.
*
* @param lineNumber the line number, 1 being the first line of the file.
* @return The line indicated. Returns {@code null} if it does not exist,
* or if there was an IO exception.
*/
public Region getRegion(int lineNumber) {
String js = "";
try {
js = getCode();
} catch (IOException e) {
return null;
}
int pos = 0;
int startLine = Math.max(1,
lineNumber - (SOURCE_EXCERPT_REGION_
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>LENGTH + 1) / 2 + 1);
for (int n = 1; n < startLine; n++) {
int nextpos = js.indexOf('\n', pos);
if (nextpos == -1) {
break;
}
pos = nextpos + 1;
}
int end = pos;
int endLine = startLine;
for (int n = 0; n < SOURCE_EXCERPT_REGION_LENGTH; n++, endLine++) {
end = js.indexOf('\n', end);
if (end == -1) {
break;
}
end++;
}
if (lineNumber >= endLine) {
return null;
}
if (end == -1) {
int last = js.length() - 1;
if (js.charAt(last) == '\n') {
return
new SimpleRegion(startLine, endLine, js.substring(pos, last));
} else {
return new SimpleRegion(startLine, endLine, js.substring(pos));
}
} else {
return new SimpleRegion(startLine, endLine, js.substring(pos, end));
}
}
public static SourceFile fromFile(String fileName, Charset c) {
return fromFile(new File(fileName), c);
}
public static SourceFile fromFile(String fileName) {
return fromFile(new File(fileName));
}
public static SourceFile fromFile(File file, Charset c) {
return new OnDisk(file, c);
}
public static SourceFile fromFile(File file) {
return new OnDisk(file);
}
public static SourceFile fromCode(String fileName, String code) {
return new Preloaded(fileName, code);
}
public static SourceFile fromCode(String fileName,
String originalPath, String code) {
return new Preloaded(fileName, originalPath, code);
}
public static SourceFile fromInputStream(String fileName, InputStream s)
throws IOException {
return fromCode(fileName,
CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8)));
}
public static SourceFile fromInputStream(String fileName,
String originalPath, InputStream s) throws IOException {
return fromCode(fileName, originalPath,
CharStreams.toString
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>(new InputStreamReader(s, Charsets.UTF_8)));
}
public static SourceFile fromReader(String fileName, Reader r)
throws IOException {
return fromCode(fileName, CharStreams.toString(r));
}
public static SourceFile fromGenerator(String fileName,
Generator generator) {
return new Generated(fileName, generator);
}
//////////////////////////////////////////////////////////////////////////////
// Implementations
/**
* A source file where the code has been preloaded.
*/
static class Preloaded extends SourceFile {
Preloaded(String fileName, String code) {
this(fileName, fileName, code);
}
Preloaded(String fileName, String originalPath, String code) {
super(fileName);
super.setOriginalPath(originalPath);
super.setCode(code);
}
}
/**
* A source file where the code will be dynamically generated
* from the injected interface.
*/
static class Generated extends SourceFile {
private final Generator generator;
// Not private, so that LazyInput can extend it.
Generated(String fileName, Generator generator) {
super(fileName);
this.generator = generator;
}
@Override
public synchronized String getCode() throws IOException {
String cachedCode = super.getCode();
if (cachedCode == null) {
cachedCode = generator.getCode();
super.setCode(cachedCode);
}
return cachedCode;
}
// Clear out the generated code when finished with a compile; we can
// regenerate it if we ever need it again.
@Override
public void clearCachedSource() {
super.setCode(null);
}
}
/**
* A source file where the code is only read into memory if absolutely
* necessary. We will try to delay loading the code into memory as long as
* possible.
*/
static class OnDisk extends SourceFile {
private final File file;
// This is stored as a String, but passed in and out as a Charset so that
// we can serialize the class.
// Default input file format for JSCompiler has always been UTF_8.
protected String inputCharset = Charsets.UTF_8.name();
OnDisk(File file, Charset c) {
this(file);
if (c != null) {
this.setCharset(c);
}
}
// No Charset provided?
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
OnDisk(File file) {
super(file.getPath());
this.file = file;
}
@Override
public synchronized String getCode() throws IOException {
String cachedCode = super.getCode();
if (cachedCode == null) {
cachedCode = Files.toString(file, this.getCharset());
super.setCode(cachedCode);
}
return cachedCode;
}
/**
* Gets a reader for the code in this source file.
*/
@Override
public Reader getCodeReader() throws IOException {
if (hasSourceInMemory()) {
return super.getCodeReader();
} else {
// If we haven't pulled the code into memory yet, don't.
return new FileReader(file);
}
}
// Flush the cached code after the compile; we can read it off disk
// if we need it again.
@Override
public void clearCachedSource() {
super.setCode(null);
}
/**
* Store the Charset specification as the string version of the name,
* rather than the Charset itself. This allows us to serialize the
* SourceFile class.
* @param c charset to use when reading the input.
*/
public void setCharset(Charset c) {
inputCharset = c.name();
}
/**
* Get the Charset specifying how we're supposed to read the file
* in off disk and into UTF-16. This is stored as a strong to allow
* SourceFile to be serialized.
* @return Charset object representing charset to use.
*/
public Charset getCharset() {
return Charset.forName(inputCharset);
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> addVar(String name) {
int vIndex = itsVariableNames.get(name, -1);
if (vIndex != -1) {
// There's already a variable or parameter with this name.
if (vIndex >= varStart) {
Object v = itsConst.get(vIndex);
if (v != null)
return DUPLICATE_CONST;
else
return DUPLICATE_VAR;
} else
return DUPLICATE_PARAMETER;
}
int index = itsVariables.size();
itsVariables.add(name);
itsConst.add(null);
itsVariableNames.put(name, index);
return NO_DUPLICATE;
}
public final boolean addConst(String name) {
int vIndex = itsVariableNames.get(name, -1);
if (vIndex != -1) {
// There's already a variable or parameter with this name.
return false;
}
int index = itsVariables.size();
itsVariables.add(name);
itsConst.add(name);
itsVariableNames.put(name, index);
return true;
}
public final void removeParamOrVar(String name) {
int i = itsVariableNames.get(name, -1);
if (i != -1) {
itsVariables.remove(i);
itsVariableNames.remove(name);
ObjToIntMap.Iterator iter = itsVariableNames.newIterator();
for (iter.start(); !iter.done(); iter.next()) {
int v = iter.getValue();
if (v > i) {
iter.setValue(v - 1);
}
}
}
}
public final Object getCompilerData()
{
return compilerData;
}
public final void setCompilerData(Object data)
{
if (data == null) throw new IllegalArgumentException();
// Can only call once
if (compilerData != null) throw new IllegalStateException();
compilerData = data;
}
private int encodedSourceStart;
private int encodedSourceEnd;
private String sourceName;
private int baseLineno = -1;
private int endLineno = -1;
private ObjArray functions;
private ObjArray regexps;
// a list of the formal parameters and local variables
private ObjArray itsVariables
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Mapping>() : null;
}
/**
* Maintains a mapping from a given node to the position
* in the source code at which its generated form was
* placed. This position is relative only to the current
* run of the CodeConsumer and will be normalized
* later on by the SourceMap.
*
* @see SourceMap
*/
private static class Mapping {
Node node;
Position start;
Position end;
}
/**
* Starts the source mapping for the given
* node at the current position.
*/
@Override
void startSourceMapping(Node node) {
if (createSrcMap
&& node.getProp(Node.SOURCEFILE_PROP) != null
&& node.getLineno() > 0) {
int line = getCurrentLineIndex();
int index = getCurrentCharIndex();
// If the index is -1, we are not performing any mapping.
if (index >= 0) {
Mapping mapping = new Mapping();
mapping.node = node;
mapping.start = new Position(line, index);
mappings.push(mapping);
allMappings.add(mapping);
}
}
}
/**
* Finishes the source mapping for the given
* node at the current position.
*/
@Override
void endSourceMapping(Node node) {
if (createSrcMap
&& node.getProp(Node.SOURCEFILE_PROP) != null
&& node.getLineno() > 0) {
int line = getCurrentLineIndex();
int index = getCurrentCharIndex();
// If the index is -1, we are not performing any mapping.
if (index >= 0) {
Preconditions.checkState(
!mappings.isEmpty(), "Mismatch in start and end of mapping");
Mapping mapping = mappings.pop();
mapping.end = new Position(line, index);
}
}
}
/**
* Generates the source map from the given code consumer,
* appending the information it saved to the SourceMap
* object given.
*/
void generateSourceMap(SourceMap map){
if (createSrcMap) {
for (Mapping mapping : allMappings) {
map.addMapping(mapping.node, mapping.start, mapping.end);
}
}
}
/**
* Reports to the code consumer that the given line
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> has been cut at the
* given position (i.e. a \n has been inserted there). All mappings in
* the source maps after that position will be renormalized as needed.
*/
void reportLineCut(int lineIndex, int charIndex) {
if (createSrcMap) {
for (Mapping mapping : allMappings) {
mapping.start = convertPosition(mapping.start, lineIndex, charIndex);
if (mapping.end != null) {
mapping.end = convertPosition(mapping.end, lineIndex, charIndex);
}
}
}
}
/**
* Converts the given position by normalizing it against the insertion
* of a newline at the given line and character position.
*
* @param position The existing position before the newline was inserted.
* @param lineIndex The index of the line at which the newline was inserted.
* @param characterPosition The position on the line at which the newline
* was inserted.
*
* @return The normalized position.
*/
private Position convertPosition(Position position, int lineIndex,
int characterPosition) {
int originalLine = position.getLineNumber();
int originalChar = position.getCharacterIndex();
if (originalLine == lineIndex && originalChar >= characterPosition) {
// If the position falls on the line itself, then normalize it
// if it falls at or after the place the newline was inserted.
return new Position(originalLine + 1, originalChar - characterPosition);
} else {
return position;
}
}
public String getCode() {
return code.toString();
}
@Override
char getLastChar() {
return (code.length() > 0) ? code.charAt(code.length() - 1) : '\0';
}
protected final int getCurrentCharIndex() {
return lineLength;
}
protected final int getCurrentLineIndex() {
return lineIndex;
}
}
static class PrettyCodePrinter
extends MappedCodePrinter {
// The number of characters after which we insert a line break in the code
static final String INDENT = " ";
private int indent = 0;
/**
* @param lineLengthThreshold The length of a line after which we force
* a newline when possible.
*/
private PrettyCodePrinter(
int
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> lineLengthThreshold, boolean createSourceMap) {
super(lineLengthThreshold, createSourceMap);
}
/**
* Appends a string to the code, keeping track of the current line length.
*/
@Override
void append(String str) {
// For pretty printing: indent at the beginning of the line
if (lineLength == 0) {
for (int i = 0; i < indent; i++) {
code.append(INDENT);
lineLength += INDENT.length();
}
}
code.append(str);
lineLength += str.length();
}
/**
* Adds a newline to the code, resetting the line length and handling
* indenting for pretty printing.
*/
@Override
void startNewLine() {
if (lineLength > 0) {
code.append('\n');
lineIndex++;
lineLength = 0;
}
}
@Override
void maybeLineBreak() {
maybeCutLine();
}
/**
* This may start a new line if the current line is longer than the line
* length threshold.
*/
@Override
void maybeCutLine() {
if (lineLength > lineLengthThreshold) {
startNewLine();
}
}
@Override
void endLine() {
startNewLine();
}
@Override
void appendBlockStart() {
append(" {");
indent++;
}
@Override
void appendBlockEnd() {
endLine();
indent--;
append("}");
}
@Override
void listSeparator() {
add(", ");
maybeLineBreak();
}
@Override
void endFunction(boolean statementContext) {
super.endFunction(statementContext);
if (statementContext) {
startNewLine();
}
}
@Override
void beginCaseBody() {
super.beginCaseBody();
indent++;
endLine();
}
@Override
void endCaseBody() {
super.endCaseBody();
indent--;
endStatement();
}
@Override
void appendOp(String op, boolean binOp) {
if (binOp) {
if (getLastChar() != ' ') {
append(" ");
}
append(op);
append(" ");
} else {
append(op);
}
}
/**
* If the body
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> of a for loop or the then clause of an if statement has
* a single statement, should it be wrapped in a block?
* {@inheritDoc}
*/
@Override
boolean shouldPreserveExtraBlocks() {
// When pretty-printing, always place the statement in its own block
// so it is printed on a separate line. This allows breakpoints to be
// placed on the statement.
return true;
}
/**
* @return The TRY node for the specified CATCH node.
*/
private Node getTryForCatch(Node n) {
return n.getParent().getParent();
}
/**
* @return Whether the a line break should be added after the specified
* BLOCK.
*/
@Override
boolean breakAfterBlockFor(Node n, boolean isStatementContext) {
Preconditions.checkState(n.getType() == Token.BLOCK);
Node parent = n.getParent();
if (parent != null) {
int type = parent.getType();
switch (type) {
case Token.DO:
// Don't break before 'while' in DO-WHILE statements.
return false;
case Token.FUNCTION:
// FUNCTIONs are handled separately, don't break here.
return false;
case Token.TRY:
// Don't break before catch
return n != parent.getFirstChild();
case Token.CATCH:
// Don't break before finally
return !NodeUtil.hasFinally(getTryForCatch(parent));
case Token.IF:
// Don't break before else
return n == parent.getLastChild();
}
}
return true;
}
}
static class CompactCodePrinter
extends MappedCodePrinter {
// The CompactCodePrinter tries to emit just enough newlines to stop there
// being lines longer than the threshold. Since the output is going to be
// gzipped, it makes sense to try to make the newlines appear in similar
// contexts so that GZIP can encode them for 'free'.
//
// This version tries to break the lines at 'preferred' places, which are
// between the top-level forms. This works because top level forms tend to
// be more uniform than arbitary legal contexts. Better compression would
// probably require explicit modelling of the gzip algorithm.
private final boolean lineBreak;
private int line
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>StartPosition = 0;
private int preferredBreakPosition = 0;
/**
* @param lineBreak break the lines a bit more aggressively
* @param lineLengthThreshold The length of a line after which we force
* a newline when possible.
* @param createSrcMap Whether to gather source position
* mapping information when printing.
*/
private CompactCodePrinter(boolean lineBreak, int lineLengthThreshold,
boolean createSrcMap) {
super(lineLengthThreshold, createSrcMap);
this.lineBreak = lineBreak;
}
/**
* Appends a string to the code, keeping track of the current line length.
*/
@Override
void append(String str) {
code.append(str);
lineLength += str.length();
}
/**
* Adds a newline to the code, resetting the line length.
*/
@Override
void startNewLine() {
if (lineLength > 0) {
code.append('\n');
lineLength = 0;
lineIndex++;
lineStartPosition = code.length();
}
}
@Override
void maybeLineBreak() {
if (lineBreak) {
if (sawFunction) {
startNewLine();
sawFunction = false;
}
}
// Since we are at a legal line break, can we upgrade the
// preferred break position? We prefer to break after a
// semicolon rather than before it.
int len = code.length();
if (preferredBreakPosition == len - 1) {
char ch = code.charAt(len - 1);
if (ch == ';') {
preferredBreakPosition = len;
}
}
maybeCutLine();
}
/**
* This may start a new line if the current line is longer than the line
* length threshold.
*/
@Override
void maybeCutLine() {
if (lineLength > lineLengthThreshold) {
// Use the preferred position provided it will break the line.
if (preferredBreakPosition > lineStartPosition &&
preferredBreakPosition < lineStartPosition + lineLength) {
int position = preferredBreakPosition;
code.insert(position, '\n');
reportLineCut(lineIndex, position - lineStartPosition);
lineIndex++;
lineLength -= (position - lineStartPosition
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>);
lineStartPosition = position + 1;
} else {
startNewLine();
}
}
}
@Override
void notePreferredLineBreak() {
preferredBreakPosition = code.length();
}
}
static class Builder {
private final Node root;
private boolean prettyPrint = false;
private boolean lineBreak = false;
private boolean outputTypes = false;
private int lineLengthThreshold = DEFAULT_LINE_LENGTH_THRESHOLD;
private SourceMap sourceMap = null;
// Specify a charset to use when outputting source code. If null,
// then just output ASCII.
private Charset outputCharset = null;
/**
* Sets the root node from which to generate the source code.
* @param node The root node.
*/
Builder(Node node) {
root = node;
}
/**
* Sets whether pretty printing should be used.
* @param prettyPrint If true, pretty printing will be used.
*/
Builder setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
return this;
}
/**
* Sets whether line breaking should be done automatically.
* @param lineBreak If true, line breaking is done automatically.
*/
Builder setLineBreak(boolean lineBreak) {
this.lineBreak = lineBreak;
return this;
}
/**
* Sets whether to output closure-style type annotations.
* @param outputTypes If true, outputs closure-style type annotations.
*/
Builder setOutputTypes(boolean outputTypes) {
this.outputTypes = outputTypes;
return this;
}
/**
* Sets the line length threshold that will be used to determine
* when to break lines, if line breaking is on.
*
* @param threshold The line length threshold.
*/
Builder setLineLengthThreshold(int threshold) {
this.lineLengthThreshold = threshold;
return this;
}
/**
* Sets the source map to which to write the metadata about
* the generated source code.
*
* @param sourceMap The source map.
*/
Builder setSourceMap(SourceMap sourceMap) {
this.sourceMap = sourceMap;
return this;
}
/**
* Set the charset to use when determining what characters need to be
* escaped in the output.
*/
Builder set
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> }
private FlowScope caseNameOrGetProp(Node name, FlowScope blindScope,
boolean outcome) {
JSType type = getTypeIfRefinable(name, blindScope);
if (type != null) {
JSType restrictedType =
type.getRestrictedTypeGivenToBooleanOutcome(outcome);
FlowScope informed = blindScope.createChildFlowScope();
declareNameInScope(informed, name, restrictedType);
return informed;
}
return blindScope;
}
private FlowScope caseTypeOf(Node node, JSType type, String value,
boolean resultEqualsValue, FlowScope blindScope) {
JSType restrictedType =
getRestrictedByTypeOfResult(type, value, resultEqualsValue);
if (restrictedType == null) {
return blindScope;
}
FlowScope informed = blindScope.createChildFlowScope();
declareNameInScope(informed, node, restrictedType);
return informed;
}
private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope,
boolean outcome) {
JSType leftType = getTypeIfRefinable(left, blindScope);
if (leftType == null) {
return blindScope;
}
JSType rightType = right.getJSType();
ObjectType targetType =
typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
if (rightType instanceof FunctionType) {
targetType = (FunctionType) rightType;
}
Visitor<JSType> visitor;
if (outcome) {
visitor = new RestrictByTrueInstanceOfResultVisitor(targetType);
} else {
visitor = new RestrictByFalseInstanceOfResultVisitor(targetType);
}
JSType restrictedLeftType = leftType.visit(visitor);
if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) {
FlowScope informed = blindScope.createChildFlowScope();
declareNameInScope(informed, left, restrictedLeftType);
return informed;
}
return blindScope;
}
/**
* Given 'property in object', ensures that the object has the property in the
* informed scope by defining it as a qualified name if the object type lacks
* the property and it's not in the blind scope.
* @param object The node of the right-
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>side of the in.
* @param propertyName The string of the left-side of the in.
*/
private FlowScope caseIn(Node object, String propertyName, FlowScope blindScope) {
JSType jsType = object.getJSType();
jsType = this.getRestrictedWithoutNull(jsType);
jsType = this.getRestrictedWithoutUndefined(jsType);
boolean hasProperty = false;
ObjectType objectType = ObjectType.cast(jsType);
if (objectType != null) {
hasProperty = objectType.hasProperty(propertyName);
}
if (!hasProperty) {
String qualifiedName = object.getQualifiedName();
if (qualifiedName != null) {
String propertyQualifiedName = qualifiedName + "." + propertyName;
if (blindScope.getSlot(propertyQualifiedName) == null) {
FlowScope informed = blindScope.createChildFlowScope();
JSType unknownType = typeRegistry.getNativeType(
JSTypeNative.UNKNOWN_TYPE);
informed.inferQualifiedSlot(
propertyQualifiedName, unknownType, unknownType);
return informed;
}
}
}
return blindScope;
}
/**
* @see SemanticReverseAbstractInterpreter#caseInstanceOf
*/
private class RestrictByTrueInstanceOfResultVisitor
extends RestrictByTrueTypeOfResultVisitor {
private final ObjectType target;
RestrictByTrueInstanceOfResultVisitor(ObjectType target) {
this.target = target;
}
@Override
protected JSType caseTopType(JSType type) {
return applyCommonRestriction(type);
}
@Override
public JSType caseUnknownType() {
if (target instanceof FunctionType) {
FunctionType funcTarget = (FunctionType) target;
if (funcTarget.hasInstanceType()) {
return funcTarget.getInstanceType();
}
}
return getNativeType(UNKNOWN_TYPE);
}
@Override
public JSType caseObjectType(ObjectType type) {
return applyCommonRestriction(type);
}
@Override
public JSType caseUnionType(UnionType type) {
return applyCommonRestriction(type);
}
@Override
public JSType caseFunctionType(FunctionType type) {
return caseObjectType(type);
}
private JSType applyCommonRestriction(JSType type) {
if (target.isUnknownType()) {
return type;
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
FunctionType funcTarget = (FunctionType) target;
if (funcTarget.hasInstanceType()) {
return type.getGreatestSubtype(funcTarget.getInstanceType());
}
return null;
}
}
/**
* @see SemanticReverseAbstractInterpreter#caseInstanceOf
*/
private class RestrictByFalseInstanceOfResultVisitor
extends RestrictByFalseTypeOfResultVisitor {
private final ObjectType target;
RestrictByFalseInstanceOfResultVisitor(ObjectType target) {
this.target = target;
}
@Override
public JSType caseObjectType(ObjectType type) {
if (target.isUnknownType()) {
return type;
}
FunctionType funcTarget = (FunctionType) target;
if (funcTarget.hasInstanceType()) {
if (type.isSubtype(funcTarget.getInstanceType())) {
return null;
}
return type;
}
return null;
}
@Override
public JSType caseUnionType(UnionType type) {
if (target.isUnknownType()) {
return type;
}
FunctionType funcTarget = (FunctionType) target;
if (funcTarget.hasInstanceType()) {
return type.getRestrictedUnion(funcTarget.getInstanceType());
}
return null;
}
@Override
public JSType caseFunctionType(FunctionType type) {
return caseObjectType(type);
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.rhino.Node;
import java.util.regex.Pattern;
/**
* This describes the Google-specific JavaScript coding conventions.
* Within Google, variable names are semantically significant.
*
*
*/
public class GoogleCodingConvention extends ClosureCodingConvention {
private static final String OPTIONAL_ARG_PREFIX = "opt_";
private static final String VAR_ARGS_NAME = "var_args";
private static final Pattern ENUM_KEY_PATTERN =
Pattern.compile("[A-Z0-9][A-Z0-9_]*");
/**
* {@inheritDoc}
*
* <p>This enforces the Google const name convention, that the first character
* after the last $ must be an upper-case letter and all subsequent letters
* must be upper case. The name must be at least 2 characters long.
*
* <p>Examples:
* <pre>
* aaa Not constant - lower-case letters in the name
* A Not constant - too short
* goog$A Constant - letters after the $ are upper-case.
* AA17 Constant - digits can appear after the first letter
* goog$7A Not constant - first character after the $ must be
* upper case.
* $A Constant - doesn't have to be anything in front of the $
* </pre>
*/
@Override
public boolean isConstant(String name) {
if (name.length() <= 1) {
return false;
}
// In compiled
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> code, '$' is often a namespace delimiter. To allow inlining
// of namespaced constants, we strip off any namespaces here.
int pos = name.lastIndexOf('$');
if (pos >= 0) {
name = name.substring(pos + 1);
if (name.length() == 0) {
return false;
}
}
return isConstantKey(name);
}
@Override
public boolean isConstantKey(String name) {
if (name.isEmpty() || !Character.isUpperCase(name.charAt(0))) {
return false;
}
// hack way of checking that there aren't any lower-case letters
return name.toUpperCase().equals(name);
}
/**
* {@inheritDoc}
*
* <p>This enforces Google's convention about enum key names. They must match
* the regular expression {@code [A-Z0-9][A-Z0-9_]*}.
*
* <p>Examples:
* <ul>
* <li>A</li>
* <li>213</li>
* <li>FOO_BAR</li>
* </ul>
*/
@Override
public boolean isValidEnumKey(String key) {
return ENUM_KEY_PATTERN.matcher(key).matches();
}
/**
* {@inheritDoc}
*
* <p>In Google code, parameter names beginning with {@code opt_} are
* treated as optional arguments.
*/
@Override
public boolean isOptionalParameter(Node parameter) {
return parameter.getString().startsWith(OPTIONAL_ARG_PREFIX);
}
@Override
public boolean isVarArgsParameter(Node parameter) {
return VAR_ARGS_NAME.equals(parameter.getString());
}
/**
* {@inheritDoc}
*
* <p>In Google code, any global name starting with an underscore is
* considered exported.
*/
@Override
public boolean isExported(String name, boolean local) {
return !local && name.startsWith("_");
}
/**
* {@inheritDoc}
*
* <p>In Google code, private names end with an underscore, and exported
* names are never considered private (see {@link #isExported}).
*/
@Override
public boolean isPrivate(String name) {
return name
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>);
}
}
private boolean hasHaltingErrors() {
return compiler.hasHaltingErrors();
}
/**
* Returns a new tracer for the given pass name.
*/
private Tracer newTracer(String passName) {
String comment = passName +
(recentChange.hasCodeChanged() ? " on recently changed AST" : "");
if (tracker != null) {
tracker.recordPassStart(passName);
}
return new Tracer("JSCompiler", comment);
}
private void stopTracer(Tracer t, String passName) {
long result = t.stop();
if (tracker != null) {
tracker.recordPassStop(passName, result);
}
}
/**
* A single compiler pass.
*/
private abstract class NamedPass implements CompilerPass {
private final String name;
NamedPass(String name) {
this.name = name;
}
public void process(Node externs, Node root) {
logger.info(name);
startPass(name);
processInternal(externs, root);
endPass(externs, root);
}
abstract void processInternal(Node externs, Node root);
}
/**
* Delegates to a PassFactory for processing.
*/
private class PassFactoryDelegate extends NamedPass {
private final AbstractCompiler myCompiler;
private final PassFactory factory;
private PassFactoryDelegate(
AbstractCompiler myCompiler, PassFactory factory) {
super(factory.getName());
this.myCompiler = myCompiler;
this.factory = factory;
}
@Override
void processInternal(Node externs, Node root) {
factory.create(myCompiler).process(externs, root);
}
}
/**
* Runs a set of compiler passes until they reach a fixed point.
*/
static abstract class Loop implements CompilerPass {
abstract void addLoopedPass(PassFactory factory);
}
/**
* Runs a set of compiler passes until they reach a fixed point.
*
* Notice that this is a non-static class, because it includes the closure
* of PhaseOptimizer.
*/
private class LoopInternal extends Loop {
private final List<NamedPass> myPasses = Lists.newArrayList();
private final Set<String> myNames = Sets.newHashSet();
@Override
void
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
/**
* Prepare the AST before we do any checks or optimizations on it.
*
* This pass must run. It should bring the AST into a consistent state,
* and add annotations where necessary. It should not make any transformations
* on the tree that would lose source information, since we need that source
* information for checks.
*
* @author johnlenz@google.com (John Lenz)
*/
class PrepareAst implements CompilerPass {
private final AbstractCompiler compiler;
private final boolean checkOnly;
PrepareAst(AbstractCompiler compiler) {
this(compiler, false);
}
PrepareAst(AbstractCompiler compiler, boolean checkOnly) {
this.compiler = compiler;
this.checkOnly = checkOnly;
}
private void reportChange() {
if (checkOnly) {
Preconditions.checkState(false, "normalizeNodeType constraints violated");
}
}
@Override
public void process(Node externs, Node root) {
if (checkOnly) {
normalizeNodeTypes(root);
} else {
// Don't perform "PrepareAnnoations" when doing checks as
// they currently aren't valid during sanity checks. In particular,
// they DIRECT_EVAL shouldn't be applied after inlining has been
// performed.
if (extern
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>s != null) {
NodeTraversal.traverse(
compiler, externs, new PrepareAnnotations(compiler));
}
if (root != null) {
NodeTraversal.traverse(
compiler, root, new PrepareAnnotations(compiler));
}
}
}
/**
* Covert EXPR_VOID to EXPR_RESULT to simplify the rest of the code.
*/
private void normalizeNodeTypes(Node n) {
if (n.getType() == Token.EXPR_VOID) {
n.setType(Token.EXPR_RESULT);
reportChange();
}
// Remove unused properties to minimize differences between ASTs
// produced by the two parsers.
if (n.getType() == Token.FUNCTION) {
Preconditions.checkState(n.getProp(Node.FUNCTION_PROP) == null);
}
normalizeBlocks(n);
for (Node child = n.getFirstChild();
child != null; child = child.getNext()) {
// This pass is run during the CompilerTestCase validation, so this
// parent pointer check serves as a more general check.
Preconditions.checkState(child.getParent() == n);
normalizeNodeTypes(child);
}
}
/**
* Add blocks to IF, WHILE, DO, etc.
*/
private void normalizeBlocks(Node n) {
if (NodeUtil.isControlStructure(n)
&& n.getType() != Token.LABEL
&& n.getType() != Token.SWITCH) {
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (NodeUtil.isControlStructureCodeBlock(n,c) &&
c.getType() != Token.BLOCK) {
Node newBlock = new Node(Token.BLOCK, n.getLineno(), n.getCharno());
newBlock.copyInformationFrom(n);
n.replaceChild(c, newBlock);
if (c.getType() != Token.EMPTY) {
newBlock.addChildrenToFront(c);
} else {
newBlock.setWasEmptyNode(true);
}
c = newBlock;
reportChange();
}
}
}
}
/**
* Normalize where annotations appear on the AST. Copies
* around existing JSDoc annotations as well as internal annotations.
*/
static class PrepareAnnotations
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> extends NodeTraversal.AbstractPostOrderCallback {
private final CodingConvention convention;
PrepareAnnotations(AbstractCompiler compiler) {
this.convention = compiler.getCodingConvention();
}
/**
*
* In the AST that Rhino gives us, it needs to make a distinction
* between jsdoc on the object literal node and jsdoc on the object literal
* value. For example,
* <pre>
* var x = {
* / JSDOC /
* a: 'b',
* c: / JSDOC / 'd'
* };
* </pre>
*
* But in few narrow cases (in particular, function literals), it's
* a lot easier for us if the doc is attached to the value.
*/
@SuppressWarnings("fallthrough")
public void visit(NodeTraversal t, Node n, Node parent) {
int nType = n.getType();
switch (nType) {
case Token.STRING:
// There are only two cases where a string token
// may be a variable reference: The right side of a GETPROP
// or an OBJECTLIT key.
if (parent.getType() != Token.OBJECTLIT &&
parent.getType() != Token.GETPROP) {
break;
}
// fall-through
case Token.NAME:
String nString = n.getString();
if (nType == Token.NAME &&
n.getParent().getType() == Token.CALL &&
"eval".equals(nString)) {
n.putBooleanProp(Node.DIRECT_EVAL, true);
}
if (NodeUtil.isConstantByConvention(convention, n, parent)) {
n.putBooleanProp(Node.IS_CONSTANT_NAME, true);
}
break;
case Token.FUNCTION:
JSDocInfo fnInfo = n.getJSDocInfo();
if (fnInfo == null) {
// Look for the info on other nodes.
if (parent.getType() == Token.ASSIGN) {
// on ASSIGNs
fnInfo = parent.getJSDocInfo();
} else if (parent.getType() == Token.NAME) {
// on var NAME = function() { ... };
fnInfo = parent.getParent().getJSDocInfo();
}
}
// Compute which function parameters are
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> the JSType from the Node argument and verifies that it is
* present.
*/
private JSType getJSType(Node n) {
JSType jsType = n.getJSType();
if (jsType == null) {
// TODO(user): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
private JSType getNativeType(JSTypeNative typeId) {
return typeRegistry.getNativeType(typeId);
}
/**
* Signals that the first type and the second type have been
* used interchangeably.
*
* Type-based optimizations should take this into account
* so that they don't wreck code with type warnings.
*/
static class TypeMismatch {
final JSType typeA;
final JSType typeB;
/**
* It's the responsibility of the class that creates the
* {@code TypeMismatch} to ensure that {@code a} and {@code b} are
* non-matching types.
*/
TypeMismatch(JSType a, JSType b) {
this.typeA = a;
this.typeB = b;
}
@Override public boolean equals(Object object) {
if (object instanceof TypeMismatch) {
TypeMismatch that = (TypeMismatch) object;
return (that.typeA.equals(this.typeA) && that.typeB.equals(this.typeB))
|| (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB));
}
return false;
}
@Override public int hashCode() {
return Objects.hashCode(typeA, typeB);
}
@Override public String toString() {
return "(" + typeA + ", " + typeB + ")";
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
this.name = name;
}
@Override
public String getReferenceName() {
return name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean isTemplateType() {
return true;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Format);
}
/**
* Create a DiagnosticType at a given CheckLevel.
*
* @param name An identifier
* @param level Either CheckLevel.ERROR or CheckLevel.WARNING
* @param descriptionFormat A format string
* @return A new DiagnosticType
*/
public static DiagnosticType make(String name, CheckLevel level,
String descriptionFormat) {
return
new DiagnosticType(name, level, new MessageFormat(descriptionFormat));
}
/**
* Create a DiagnosticType. Private to force use of static factory methods.
*/
private DiagnosticType(String key, CheckLevel level, MessageFormat format) {
this.key = key;
this.defaultLevel = level;
this.format = format;
this.level = this.defaultLevel;
}
/**
* Create a description from the MessageFormat and the arguments.
* Used by unit tests.
*/
String format(Object ... arguments) {
return format.format(arguments);
}
@Override
public int compareTo(DiagnosticType diagnosticType) {
return key.compareTo(diagnosticType.key);
}
@Override
public String toString() {
return key + ": " + format.toPattern();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.TernaryValue.FALSE;
import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN;
/**
* Boolean type.
*
*/
public class BooleanType extends ValueType {
private static final long serialVersionUID = 1L;
BooleanType(JSTypeRegistry registry) {
super(registry);
}
@
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Override
public boolean isNullable() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isUnknownType() || that.isSubtype(
getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) ||
that.isObject()) {
return UNKNOWN;
}
return FALSE;
}
@Override
public boolean isBooleanValueType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
// TODO(user): Revisit this for ES4, which is stricter.
return true;
}
@Override
public JSType autoboxesTo() {
return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
}
@Override
public String toString() {
return "boolean";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseBooleanType();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>();
for (Name name : namespace.getNameIndex().values()) {
if (name.docInfo != null && name.docInfo.isDefine()) {
// Process defines should not depend on check types being enabled,
// so we look for the JSDoc instead of the inferred type.
if (isValidDefineType(name.docInfo.getType())) {
allDefines.add(name);
} else {
JSError error = JSError.make(
name.declaration.sourceName,
name.declaration.node,
INVALID_DEFINE_TYPE_ERROR);
compiler.report(error);
}
} else if (name.refs != null) {
for (Ref ref : name.refs) {
Node n = ref.node;
Node parent = ref.node.getParent();
JSDocInfo info = n.getJSDocInfo();
if (info == null &&
parent.getType() == Token.VAR && parent.hasOneChild()) {
info = parent.getJSDocInfo();
}
if (info != null && info.isDefine()) {
allDefines.add(name);
break;
}
}
}
}
CollectDefines pass = new CollectDefines(compiler, allDefines);
NodeTraversal.traverse(compiler, root, pass);
return pass.getAllDefines();
}
/**
* Finds all assignments to @defines, and figures out the last value of
* the @define.
*/
private static final class CollectDefines implements Callback {
private final AbstractCompiler compiler;
private final Map<String, DefineInfo> assignableDefines;
private final Map<String, DefineInfo> allDefines;
private final Map<Node, RefInfo> allRefInfo;
// A hack that allows us to remove ASSIGN/VAR statements when
// we're currently visiting one of the children of the assign.
private Node lvalueToRemoveLater = null;
// A stack tied to the node traversal, to keep track of whether
// we're in a conditional block. If 1 is at the top, assignment to
// a define is allowed. Otherwise, it's not allowed.
private final Deque<Integer> assignAllowed;
CollectDefines(AbstractCompiler compiler, List<Name> listOfDefines) {
this.compiler = compiler;
this.allDefines = Maps.newHashMap();
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> assignableDefines = Maps.newHashMap();
assignAllowed = new ArrayDeque<Integer>();
assignAllowed.push(1);
// Create a map of references to defines keyed by node for easy lookup
allRefInfo = Maps.newHashMap();
for (Name name : listOfDefines) {
if (name.declaration != null) {
allRefInfo.put(name.declaration.node,
new RefInfo(name.declaration, name));
}
if (name.refs != null) {
for (Ref ref : name.refs) {
// If there's a TWIN def, only put one of the twins in.
if (ref.getTwin() == null || !ref.getTwin().isSet()) {
allRefInfo.put(ref.node, new RefInfo(ref, name));
}
}
}
}
}
/**
* Get a map of {@link DefineInfo} structures, keyed by the name of
* the define.
*/
Map<String, DefineInfo> getAllDefines() {
return allDefines;
}
/**
* Keeps track of whether the traversal is in a conditional branch.
* We traverse all nodes of the parse tree.
*/
public boolean shouldTraverse(NodeTraversal nodeTraversal, Node n,
Node parent) {
updateAssignAllowedStack(n, true);
return true;
}
public void visit(NodeTraversal t, Node n, Node parent) {
RefInfo refInfo = allRefInfo.get(n);
if (refInfo != null) {
Ref ref = refInfo.ref;
Name name = refInfo.name;
String fullName = name.fullName();
switch (ref.type) {
case SET_FROM_GLOBAL:
case SET_FROM_LOCAL:
Node valParent = getValueParent(ref);
Node val = valParent.getLastChild();
if (valParent.getType() == Token.ASSIGN && name.isSimpleName() &&
name.declaration == ref) {
// For defines, it's an error if a simple name is assigned
// before it's declared
compiler.report(
t.makeError(val, INVALID_DEFINE_INIT_ERROR, fullName));
} else if (processDefineAssignment(t, fullName, val, valParent)) {
// remove the assignment so that the
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>} until requested by
* {@link #getControlFlowGraph()}. Note that {@link ArrayDeque} does not allow
* {@code null} elements, so {@link LinkedList} is used instead.
*/
Deque<ControlFlowGraph<Node>> cfgs = new LinkedList<ControlFlowGraph<Node>>();
/** The current source file name */
private String sourceName;
/** The scope creator */
private ScopeCreator scopeCreator;
/** Possible callback for scope entry and exist **/
private ScopedCallback scopeCallback;
/**
* Callback
*/
public interface Callback {
/**
* <p>Visits a node in pre order (before visiting its children) and decides
* whether this node's children should be traversed. If children are
* traversed, they will be visited by
* {@link #visit(NodeTraversal, Node, Node)} in post order.</p>
* <p>Implementations can have side effects (e.g. modifying the parse
* tree).</p>
* @return whether the children of this node should be visited
*/
boolean shouldTraverse(NodeTraversal nodeTraversal, Node n, Node parent);
/**
* <p>Visits a node in post order (after its children have been visited).
* A node is visited only if all its parents should be traversed
* ({@link #shouldTraverse(NodeTraversal, Node, Node)}).</p>
* <p>Implementations can have side effects (e.g. modifying the parse
* tree).</p>
*/
void visit(NodeTraversal t, Node n, Node parent);
}
/**
* Callback that also knows about scope changes
*/
public interface ScopedCallback extends Callback {
/**
* Called immediately after entering a new scope. The new scope can
* be accessed through t.getScope()
*/
void enterScope(NodeTraversal t);
/**
* Called immediately before exiting a scope. The ending scope can
* be accessed through t.getScope()
*/
void exitScope(NodeTraversal t);
}
/**
* Abstract callback to visit all nodes in post order.
*
*/
public abstract static class AbstractPostOrderCallback implements Callback {
public final boolean shouldTraverse(NodeTraversal nodeTraversal, Node n,
Node parent) {
return true;
}
}
/**
* Abstract callback to
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
if (cb instanceof ScopedCallback) {
this.scopeCallback = (ScopedCallback) cb;
}
this.compiler = compiler;
this.sourceName = "";
this.scopeCreator = scopeCreator;
}
private void throwUnexpectedException(Exception unexpectedException) {
// If there's an unexpected exception, try to get the
// line number of the code that caused it.
String message = unexpectedException.getMessage();
// TODO(user): It is possible to get more information if curNode or
// its parent is missing. We still have the scope stack in which it is still
// very useful to find out at least which function caused the exception.
if (!sourceName.isEmpty()) {
message =
unexpectedException.getMessage() + "\n" +
formatNodeContext("Node", curNode) +
(curNode == null ?
"" :
formatNodeContext("Parent", curNode.getParent()));
}
compiler.throwInternalError(message, unexpectedException);
}
private String formatNodeContext(String label, Node n) {
if (n == null) {
return " " + label + ": NULL";
}
return " " + label + "(" + n.toString(false, false, false) + "): "
+ formatNodePosition(n);
}
/**
* Traverses a parse tree recursively.
*/
public void traverse(Node root) {
try {
sourceName = "";
curNode = root;
pushScope(root);
traverseBranch(root, null);
popScope();
} catch (Exception unexpectedException) {
throwUnexpectedException(unexpectedException);
}
}
public void traverseRoots(Node ... roots) {
traverseRoots(Lists.newArrayList(roots));
}
public void traverseRoots(List<Node> roots) {
if (roots.isEmpty()) {
return;
}
try {
Node scopeRoot = roots.get(0).getParent();
Preconditions.checkState(scopeRoot != null);
sourceName = "";
curNode = scopeRoot;
pushScope(scopeRoot);
for (Node root : roots) {
Preconditions.checkState(root.getParent() == scopeRoot);
traverseBranch(root, scopeRoot);
}
popScope();
} catch (Exception unexpectedException) {
throwUnexpectedException(unexpectedException
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>code null}
*/
protected void traverseInnerNode(Node node, Node parent, Scope refinedScope) {
Preconditions.checkNotNull(parent);
if (refinedScope != null && getScope() != refinedScope) {
curNode = node;
pushScope(refinedScope);
traverseBranch(node, parent);
popScope();
} else {
traverseBranch(node, parent);
}
}
/**
* Gets the compiler.
*/
public Compiler getCompiler() {
// TODO(nicksantos): Remove this type cast. This is just temporary
// while refactoring.
return (Compiler) compiler;
}
/**
* Gets the current line number, or zero if it cannot be determined. The line
* number is retrieved lazily as a running time optimization.
*/
public int getLineNumber() {
Node cur = curNode;
while (cur != null) {
int line = cur.getLineno();
if (line >=0) {
return line;
}
cur = cur.getParent();
}
return 0;
}
/**
* Gets the current input source name.
*
* @return A string that may be empty, but not null
*/
public String getSourceName() {
return sourceName;
}
/**
* Gets the current input source.
*/
public CompilerInput getInput() {
return compiler.getInput(sourceName);
}
/**
* Gets the current input module.
*/
public JSModule getModule() {
CompilerInput input = getInput();
return input == null ? null : input.getModule();
}
/** Returns the node currently being traversed. */
public Node getCurrentNode() {
return curNode;
}
/**
* Traverses a node recursively.
*/
public static void traverse(
AbstractCompiler compiler, Node root, Callback cb) {
NodeTraversal t = new NodeTraversal(compiler, cb);
t.traverse(root);
}
/**
* Traverses a list of node trees.
*/
public static void traverseRoots(
AbstractCompiler compiler, List<Node> roots, Callback cb) {
NodeTraversal t = new NodeTraversal(compiler, cb);
t.traverseRoots(roots);
}
/**
* Traverses a branch.
*/
@SuppressWarnings("
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>fallthrough")
private void traverseBranch(Node n, Node parent) {
int type = n.getType();
if (type == Token.SCRIPT) {
sourceName = getSourceName(n);
}
curNode = n;
if (!callback.shouldTraverse(this, n, parent)) return;
switch (type) {
case Token.CATCH:
Preconditions.checkState(n.getChildCount() == 3);
Preconditions.checkState(n.getFirstChild().getType() == Token.NAME);
// the first child is the catch var and the third child
// is the code block
traverseBranch(n.getFirstChild(), n);
traverseBranch(n.getFirstChild().getNext().getNext(), n);
break;
case Token.FUNCTION:
traverseFunction(n, parent);
break;
default:
for (Node child = n.getFirstChild(); child != null; ) {
// child could be replaced, in which case our child node
// would no longer point to the true next
Node next = child.getNext();
traverseBranch(child, n);
child = next;
}
break;
}
curNode = n;
callback.visit(this, n, parent);
}
/**
* Traverses a function.
*/
private void traverseFunction(Node n, Node parent) {
Preconditions.checkState(n.getChildCount() == 3);
Preconditions.checkState(n.getType() == Token.FUNCTION);
final Node fnName = n.getFirstChild();
boolean isFunctionExpression = (parent != null)
&& NodeUtil.isFunctionExpression(n);
if (!isFunctionExpression) {
// Functions declarations are in the scope containing the declaration.
traverseBranch(fnName, n);
}
curNode = n;
pushScope(n);
if (isFunctionExpression) {
// Function expression names are only accessible within the function
// scope.
traverseBranch(fnName, n);
}
final Node args = fnName.getNext();
final Node body = args.getNext();
// Args
traverseBranch(args, n);
// Body
Preconditions.checkState(body.getNext() == null &&
body.getType() == Token.BLOCK);
traverseBranch(body, n);
popScope();
}
/** Examines the functions stack for
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>provide/goog.require calls, and prune inputs
* whose symbols are not required.
*/
public void setManageClosureDependencies(boolean newVal) {
manageClosureDependencies = newVal;
}
/**
* Controls how detailed the compilation summary is. Values:
* 0 (never print summary), 1 (print summary only if there are
* errors or warnings), 2 (print summary if type checking is on,
* see --check_types), 3 (always print summary). The default level
* is 1
*/
public void setSummaryDetailLevel(int summaryDetailLevel) {
this.summaryDetailLevel = summaryDetailLevel;
}
public void enableExternExports(boolean enable) {
this.externExports = enable;
}
public boolean isExternExportsEnabled() {
return externExports;
}
/**
* Whether to include "undefined" in the default types.
* For example:
* "{Object}" is normally "Object|null" becomes "Object|null|undefined"
* "{?string}" is normally "string|null" becomes "string|null|undefined"
* In either case "!" annotated types excluded both null and undefined.
*/
public void setLooseTypes(boolean looseTypes) {
this.looseTypes = looseTypes;
}
@Override
public Object clone() throws CloneNotSupportedException {
CompilerOptions clone = (CompilerOptions) super.clone();
// TODO(bolinfest): Add relevant custom cloning.
return clone;
}
//////////////////////////////////////////////////////////////////////////////
// Enums
/** When to do the extra sanity checks */
static enum DevMode {
/**
* Don't do any extra sanity checks.
*/
OFF,
/**
* After the initial parse
*/
START,
/**
* At the start and at the end of all optimizations.
*/
START_AND_END,
/**
* After every pass
*/
EVERY_PASS
}
public static enum TracerMode {
ALL, // Collect all timing and size metrics.
FAST, // Collect all timing and size metrics, except gzipped size.
OFF; // Collect no timing and size metrics.
boolean isOn() {
return this != OFF;
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
/**
* An AST generated totally by the compiler.
*
* @author nicksantos@google.com (Nick Santos)
*/
class SyntheticAst implements SourceAst {
private static final long serialVersionUID = 1L;
private final String sourceName;
private Node root;
SyntheticAst(String sourceName) {
this.sourceName = sourceName;
clearAst();
}
@Override
public Node getAstRoot(AbstractCompiler compiler) {
return root;
}
@Override
public void clearAst() {
root = new Node(Token.SCRIPT);
root.putProp(Node.SOURCENAME_PROP, sourceName);
}
@Override
public SourceFile getSourceFile() {
return null;
}
@Override
public void setSourceFile(SourceFile file) {
throw new IllegalStateException(
"Cannot set a source file for a synthetic AST");
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> @Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isUnknownType() || that.isSubtype(
getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) {
return UNKNOWN;
}
return FALSE;
}
@Override
public boolean isStringValueType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
// TODO(user): Revisit this for ES4, which is stricter.
return true;
}
@Override
public String toString() {
return "string";
}
@Override
public JSType autoboxesTo() {
return getNativeType(JSTypeNative.STRING_OBJECT_TYPE);
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseStringType();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.collect.Lists;
import com.google.javascript.jscomp.CheckLevel;
import java.util.*;
/**
* WarningsGuard that represents just a chain of other guards. For example we
* could have following chain
* 1) all warnings outside of /foo/ should be suppressed
* 2) errors with key JSC_BAR should be marked as warning
* 3) the rest should be reported as error
*
* This class is designed for such behaviour.
*
* @author anatol@google.com (Anatol Pomazau)
*/
public class ComposeWarningsGuard extends WarningsGuard {
private final List<WarningsGuard> guards;
private static final Comparator<WarningsGuard> guardComparator =
new Comparator<WarningsGuard>() {
@Override
public int compare(WarningsGuard a, WarningsGuard b) {
return a.getPriority() - b.getPriority();
}
};
public ComposeWarningsGuard(List<WarningsGuard> guards) {
this.guards = Lists.newArrayList();
addGuards(guards);
}
public ComposeWarningsGuard(WarningsGuard... guards) {
this(Lists.newArrayList(guards));
}
void addGuard(WarningsGuard guard) {
if (guard instanceof ComposeWarningsGuard) {
addGuards(((ComposeWarningsGuard) guard).guards);
} else {
int index = Collections.binarySearch(this.guards, guard, guardComparator);
if (index < 0) {
index = -index - 1;
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> }
this.guards.add(index, guard);
}
}
private void addGuards(Iterable<WarningsGuard> guards) {
for (WarningsGuard guard : guards) {
addGuard(guard);
}
}
@Override
public CheckLevel level(JSError error) {
for (WarningsGuard guard : guards) {
CheckLevel newLevel = guard.level(error);
if (newLevel != null) {
return newLevel;
}
}
return null;
}
@Override
public boolean disables(DiagnosticGroup group) {
nextSingleton:
for (DiagnosticType type : group.getTypes()) {
DiagnosticGroup singleton = DiagnosticGroup.forType(type);
for (WarningsGuard guard : guards) {
if (guard.disables(singleton)) {
continue nextSingleton;
} else if (guard.enables(singleton)) {
return false;
}
}
return false;
}
return true;
}
/**
* Determines whether this guard will "elevate" the status of any disabled
* diagnostic type in the group to a warning or an error.
*/
@Override
public boolean enables(DiagnosticGroup group) {
for (WarningsGuard guard : guards) {
if (guard.enables(group)) {
return true;
}
}
return false;
}
List<WarningsGuard> getGuards() {
return Collections.unmodifiableList(guards);
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> it.
*/
static JSModule[] createModuleChain(String... inputs) {
JSModule[] modules = createModules(inputs);
for (int i = 1; i < modules.length; i++) {
modules[i].addDependency(modules[i - 1]);
}
return modules;
}
/**
* Generates a list of modules from a list of inputs, such that each module
* depends on the first module.
*/
static JSModule[] createModuleStar(String... inputs) {
JSModule[] modules = createModules(inputs);
for (int i = 1; i < modules.length; i++) {
modules[i].addDependency(modules[0]);
}
return modules;
}
/**
* Generates a list of modules from a list of inputs. Does not generate any
* dependencies between the modules.
*/
static JSModule[] createModules(String... inputs) {
JSModule[] modules = new JSModule[inputs.length];
for (int i = 0; i < inputs.length; i++) {
JSModule module = modules[i] = new JSModule("m" + i);
module.add(JSSourceFile.fromCode("i" + i, inputs[i]));
}
return modules;
}
private static class BlackHoleErrorManager extends BasicErrorManager {
private BlackHoleErrorManager(Compiler compiler) {
compiler.setErrorManager(this);
}
@Override
public void println(CheckLevel level, JSError error) {}
@Override
public void printSummary() {}
}
private Compiler createCompiler() {
Compiler compiler = new Compiler();
return compiler;
}
protected void setExpectedSymbolTableError(DiagnosticType type) {
this.expectedSymbolTableError = type;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Type) {
super(registry, objectType);
this.indexType = indexType;
}
@Override
public JSType getIndexType() {
return indexType;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Native.
private final boolean isChecked;
UnknownType(JSTypeRegistry registry, boolean isChecked) {
super(registry);
this.isChecked = isChecked;
}
@Override
public boolean isUnknownType() {
return true;
}
@Override
public boolean isCheckedUnknownType() {
return isChecked;
}
@Override
public boolean canAssignTo(JSType that) {
return true;
}
@Override
public boolean canBeCalled() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public TernaryValue testForEquality(JSType that) {
return UNKNOWN;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
return true;
}
@Override
public JSType getLeastSupertype(JSType that) {
return this;
}
@Override
public JSType getGreatestSubtype(JSType that) {
return this;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnknownType();
}
@Override
public String toString() {
return getReferenceName();
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns) {
// nothing to define
return true;
}
@Override
public ObjectType getImplicitPrototype() {
return null;
}
@Override
public int getPropertiesCount() {
return Integer.MAX_VALUE;
}
@Override
void collectPropertyNames(Set<String> props) {
}
@Override
public JSType getPropertyType(String propertyName) {
return this;
}
@Override
public boolean hasProperty(String propertyName) {
return true;
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
public String getReferenceName() {
return isChecked ? "??" : "?";
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return false;
}
@Override
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
public boolean isPropertyTypeInferred(String propertyName) {
return false;
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
return this;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> reference is resolved.
*
* The {@code UnresolvedType} will behave like an opaque unknown type.
* When its {@code #resolve} method is called, it will return the underlying
* type. The underlying type can resolve to any JS type.<p>
*
* @author nicksantos@google.com (Nick Santos)
*/
class UnresolvedTypeExpression extends UnknownType {
private static final long serialVersionUID = 1L;
private final Node typeExpr;
private final String sourceName;
/**
* If true, don't warn about unresolveable type names.
*
* NOTE(nicksantos): A lot of third-party code doesn't use our type syntax.
* They have code like
* {@code @return} the bus.
* and they clearly don't mean that "the" is a type. In these cases, we're
* forgiving and try to guess whether or not "the" is a type when it's not
* clear.
*/
private boolean forgiving = false;
/**
* Create a named type based on the reference.
*/
UnresolvedTypeExpression(JSTypeRegistry registry, Node typeExpr,
String sourceName, boolean forgiving) {
super(registry, false);
Preconditions.checkNotNull(typeExpr);
this.typeExpr = typeExpr;
this.sourceName = sourceName;
this.forgiving = forgiving;
}
/**
* Resolve the referenced type within the enclosing scope.
*/
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) {
return registry.createFromTypeNodes(typeExpr, sourceName, enclosing,
forgiving);
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>IN_EXTERNS_ERROR =
DiagnosticType.warning(
"JSC_NAME_REFERENCE_IN_EXTERNS",
"accessing name {0} in externs has no effect");
static final DiagnosticType UNDEFINED_EXTERN_VAR_ERROR =
DiagnosticType.disabled(
"JSC_UNDEFINED_EXTERN_VAR_ERROR",
"name {0} is not undefined in the externs.");
static final DiagnosticType INVALID_FUNCTION_DECL =
DiagnosticType.error("JSC_INVALID_FUNCTION_DECL",
"Syntax error: function declaration must have a name");
private CompilerInput synthesizedExternsInput = null;
private Node synthesizedExternsRoot = null;
private final AbstractCompiler compiler;
// Whether this is the post-processing sanity check.
private final boolean sanityCheck;
// Whether extern checks emit error.
private boolean strictExternCheck;
VarCheck(AbstractCompiler compiler) {
this(compiler, false);
}
VarCheck(AbstractCompiler compiler, boolean sanityCheck) {
this.compiler = compiler;
this.strictExternCheck = compiler.getErrorLevel(
JSError.make("", 0, 0, UNDEFINED_EXTERN_VAR_ERROR)) == CheckLevel.ERROR;
this.sanityCheck = sanityCheck;
}
@Override
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, externs, new NameRefInExternsCheck());
NodeTraversal.traverseRoots(
compiler, Lists.newArrayList(externs, root), this);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() != Token.NAME) {
return;
}
String varName = n.getString();
// Only a function can have an empty name.
if (varName.isEmpty()) {
Preconditions.checkState(NodeUtil.isFunction(parent));
// A function declaration with an empty name passes Rhino,
// but is supposed to be a syntax error according to the spec.
if (!NodeUtil.isFunctionExpression(parent)) {
t.report(n, INVALID_FUNCTION_DECL);
}
return;
}
// Check that the var has been declared.
Scope scope = t.getScope();
Scope.Var var = scope
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.isGlobal()) {
if (moduleGraph.dependsOn(varModule, currModule)) {
// The variable reference violates a declared module dependency.
t.report(n, VIOLATED_MODULE_DEP_ERROR,
currModule.getName(), varModule.getName(), varName);
} else {
// The variable reference is between two modules that have no
// dependency relationship. This should probably be considered an
// error, but just issue a warning for now.
t.report(n, MISSING_MODULE_DEP_ERROR,
currModule.getName(), varModule.getName(), varName);
}
} else {
t.report(n, STRICT_MODULE_DEP_ERROR,
currModule.getName(), varModule.getName(), varName);
}
}
}
}
/**
* A check for name references in the externs inputs. These used to prevent
* a variable from getting renamed, but no longer have any effect.
*/
private class NameRefInExternsCheck extends AbstractPostOrderCallback {
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.NAME) {
switch (parent.getType()) {
case Token.VAR:
case Token.FUNCTION:
case Token.LP:
// These are okay.
break;
case Token.GETPROP:
if (n == parent.getFirstChild()) {
Scope scope = t.getScope();
Scope.Var var = scope.getVar(n.getString());
if (var == null) {
t.report(n, UNDEFINED_EXTERN_VAR_ERROR, n.getString());
}
}
break;
default:
t.report(n, NAME_REFERENCE_IN_EXTERNS_ERROR, n.getString());
break;
}
}
}
}
/** Lazily create a "new" externs input for undeclared variables. */
private CompilerInput getSynthesizedExternsInput() {
if (synthesizedExternsInput == null) {
synthesizedExternsInput =
compiler.newExternInput("{SyntheticVarsDeclar}");
}
return synthesizedExternsInput;
}
/** Lazily create a "new" externs root for undeclared variables. */
private Node getSynt
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
private static final long serialVersionUID = 1L;
VoidType(JSTypeRegistry registry) {
super(registry);
}
@Override
public JSType restrictByNotNullOrUndefined() {
return registry.getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isSubtype(this) ||
that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) {
return TRUE;
}
return FALSE;
}
@Override
public boolean matchesNumberContext() {
return false;
}
@Override
public boolean matchesObjectContext() {
return false;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean isVoidType() {
return true;
}
@Override
public String toString() {
return "undefined";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.FALSE;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseVoidType();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> /** Gets the module name. */
public String getName() {
return name;
}
@Override
public List<String> getProvides() {
return ImmutableList.<String>of(name);
}
@Override
public List<String> getRequires() {
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (JSModule m : deps) {
builder.add(m.getName());
}
return builder.build();
}
@Override
public String getPathRelativeToClosureBase() {
throw new UnsupportedOperationException();
}
/** Adds a source file input to this module. */
public void add(JSSourceFile file) {
add(new CompilerInput(file));
}
/** Adds a source file input to this module. */
public void addFirst(JSSourceFile file) {
addFirst(new CompilerInput(file));
}
/** Adds a source code input to this module. */
public void add(CompilerInput input) {
inputs.add(input);
input.setModule(this);
}
/** Adds a source code input to this module. */
public void addFirst(CompilerInput input) {
inputs.add(0, input);
input.setModule(this);
}
/** Adds a source code input to this module directly after other. */
public void addAfter(CompilerInput input, CompilerInput other) {
Preconditions.checkState(inputs.contains(other));
inputs.add(inputs.indexOf(other), input);
input.setModule(this);
}
/** Adds a dependency on another module. */
public void addDependency(JSModule dep) {
Preconditions.checkState(dep != this);
deps.add(dep);
}
/** Removes an input from this module. */
public void remove(CompilerInput input) {
input.setModule(null);
inputs.remove(input);
}
/** Removes all of the inputs from this module. */
public void removeAll() {
for (CompilerInput input : inputs) {
input.setModule(null);
}
inputs.clear();
}
/**
* Gets the list of modules that this module depends on.
*
* @return A list that may be empty but not null
*/
public List<JSModule> getDependencies() {
return deps;
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
/**
* Gets the names of the modules that this module depends on,
* sorted alphabetically.
*/
List<String> getSortedDependencyNames() {
List<String> names = Lists.newArrayList();
for (JSModule module : getDependencies()) {
names.add(module.getName());
}
Collections.sort(names);
return names;
}
/**
* Returns the transitive closure of dependencies starting from the
* dependencies of this module.
*/
public Set<JSModule> getAllDependencies() {
Set<JSModule> allDeps = Sets.newHashSet(deps);
List<JSModule> workList = Lists.newArrayList(deps);
while (workList.size() > 0) {
JSModule module = workList.remove(workList.size() - 1);
for (JSModule dep : module.getDependencies()) {
if (allDeps.add(dep)) {
workList.add(dep);
}
}
}
return allDeps;
}
/** Returns this module and all of its dependencies in one list. */
public Set<JSModule> getThisAndAllDependencies() {
Set<JSModule> deps = getAllDependencies();
deps.add(this);
return deps;
}
/**
* Gets this module's list of source code inputs.
*
* @return A list that may be empty but not null
*/
public List<CompilerInput> getInputs() {
return inputs;
}
/** Returns the input with the given name or null if none. */
public CompilerInput getByName(String name) {
for (CompilerInput input : inputs) {
if (name.equals(input.getName())) {
return input;
}
}
return null;
}
/**
* Removes any input with the given name. Returns whether any were removed.
*/
public boolean removeByName(String name) {
boolean found = false;
Iterator<CompilerInput> iter = inputs.iterator();
while (iter.hasNext()) {
CompilerInput file = iter.next();
if (name.equals(file.getName())) {
iter.remove();
file.setModule(null);
found = true;
}
}
return found;
}
/** Returns the module name (primarily for debugging). */
@Override
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> qualifiedName = node.getQualifiedName();
Preconditions.checkNotNull(qualifiedName);
JSType origType = node.getJSType();
origType = origType == null ? getNativeType(UNKNOWN_TYPE) : origType;
scope.inferQualifiedSlot(qualifiedName, origType, type);
break;
default:
throw new IllegalArgumentException("Node cannot be refined. \n" +
node.toStringTree());
}
}
/**
* @see #getRestrictedWithoutUndefined(JSType)
*/
private final Visitor<JSType> restrictUndefinedVisitor =
new Visitor<JSType>() {
public JSType caseEnumElementType(EnumElementType enumElementType) {
JSType type = enumElementType.getPrimitiveType().visit(this);
if (type != null && enumElementType.getPrimitiveType().equals(type)) {
return enumElementType;
} else {
return type;
}
}
public JSType caseAllType() {
return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE,
STRING_TYPE, BOOLEAN_TYPE, NULL_TYPE);
}
public JSType caseNoObjectType() {
return getNativeType(NO_OBJECT_TYPE);
}
public JSType caseNoType() {
return getNativeType(NO_TYPE);
}
public JSType caseBooleanType() {
return getNativeType(BOOLEAN_TYPE);
}
public JSType caseFunctionType(FunctionType type) {
return type;
}
public JSType caseNullType() {
return getNativeType(NULL_TYPE);
}
public JSType caseNumberType() {
return getNativeType(NUMBER_TYPE);
}
public JSType caseObjectType(ObjectType type) {
return type;
}
public JSType caseStringType() {
return getNativeType(STRING_TYPE);
}
public JSType caseUnionType(UnionType type) {
return type.getRestrictedUnion(getNativeType(VOID_TYPE));
}
public JSType caseUnknownType() {
return getNativeType(UNKNOWN_TYPE);
}
public JSType caseVoidType() {
return null;
}
};
/**
* @see #getRestrictedWithoutNull(JSType)
*/
private final Visitor<JSType> restrictNullVisitor =
new Visitor<JSType>() {
public JS
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Type caseEnumElementType(EnumElementType enumElementType) {
JSType type = enumElementType.getPrimitiveType().visit(this);
if (type != null && enumElementType.getPrimitiveType().equals(type)) {
return enumElementType;
} else {
return type;
}
}
public JSType caseAllType() {
return typeRegistry.createUnionType(OBJECT_TYPE, NUMBER_TYPE,
STRING_TYPE, BOOLEAN_TYPE, VOID_TYPE);
}
public JSType caseNoObjectType() {
return getNativeType(NO_OBJECT_TYPE);
}
public JSType caseNoType() {
return getNativeType(NO_TYPE);
}
public JSType caseBooleanType() {
return getNativeType(BOOLEAN_TYPE);
}
public JSType caseFunctionType(FunctionType type) {
return type;
}
public JSType caseNullType() {
return null;
}
public JSType caseNumberType() {
return getNativeType(NUMBER_TYPE);
}
public JSType caseObjectType(ObjectType type) {
return type;
}
public JSType caseStringType() {
return getNativeType(STRING_TYPE);
}
public JSType caseUnionType(UnionType type) {
return type.getRestrictedUnion(getNativeType(NULL_TYPE));
}
public JSType caseUnknownType() {
return getNativeType(UNKNOWN_TYPE);
}
public JSType caseVoidType() {
return getNativeType(VOID_TYPE);
}
};
/**
* A class common to all visitors that need to restrict the type based on
* {@code typeof}-like conditions.
*/
abstract class RestrictByTypeOfResultVisitor
implements Visitor<JSType> {
/**
* Abstracts away the similarities between visiting the unknown type and the
* all type.
* @param topType {@code UNKNOWN_TYPE} or {@code ALL_TYPE}
* @return the restricted type
* @see #caseAllType
* @see #caseUnknownType
*/
protected abstract JSType caseTopType(JSType topType);
public JSType caseAllType() {
return caseTopType(getNativeType(ALL_TYPE));
}
public JSType caseUnknownType() {
return caseTopType(getNativeType(UNKNOWN_TYPE
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>));
}
public JSType caseUnionType(UnionType type) {
JSType restricted = null;
for (JSType alternate : type.getAlternates()) {
JSType restrictedAlternate = alternate.visit(this);
if (restrictedAlternate != null) {
if (restricted == null) {
restricted = restrictedAlternate;
} else {
restricted = restrictedAlternate.getLeastSupertype(restricted);
}
}
}
return restricted;
}
public JSType caseNoType() {
return getNativeType(NO_TYPE);
}
public JSType caseEnumElementType(EnumElementType enumElementType) {
// NOTE(nicksantos): This is a white lie. Suppose we have:
// /** @enum {string|number} */ var MyEnum = ...;
// if (goog.isNumber(myEnumInstance)) {
// /* what is myEnumInstance here? */
// }
// There is no type that represents {MyEnum - string}. What we really
// need is a notion of "enum subtyping", so that we could dynamically
// create a subtype of MyEnum restricted by string. In any case,
// this should catch the common case.
JSType type = enumElementType.getPrimitiveType().visit(this);
if (type != null && enumElementType.getPrimitiveType().equals(type)) {
return enumElementType;
} else {
return type;
}
}
}
/**
* A class common to all visitors that need to restrict the type based on
* some {@code typeof}-like condition being true. All base cases return
* {@code null}. It is up to the subclasses to override the appropriate ones.
*/
abstract class RestrictByTrueTypeOfResultVisitor
extends RestrictByTypeOfResultVisitor {
public JSType caseNoObjectType() {
return null;
}
public JSType caseBooleanType() {
return null;
}
public JSType caseFunctionType(FunctionType type) {
return null;
}
public JSType caseNullType() {
return null;
}
public JSType caseNumberType() {
return null;
}
public JSType caseObjectType(ObjectType type) {
return null;
}
public JSType caseStringType() {
return null;
}
public JSType caseVoidType() {
return null
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>;
}
}
/**
* A class common to all visitors that need to restrict the type based on
* some {@code typeof}-like condition being false. All base cases return
* their type. It is up to the subclasses to override the appropriate ones.
*/
abstract class RestrictByFalseTypeOfResultVisitor
extends RestrictByTypeOfResultVisitor {
@Override
protected JSType caseTopType(JSType topType) {
return topType;
}
public JSType caseNoObjectType() {
return getNativeType(NO_OBJECT_TYPE);
}
public JSType caseBooleanType() {
return getNativeType(BOOLEAN_TYPE);
}
public JSType caseFunctionType(FunctionType type) {
return type;
}
public JSType caseNullType() {
return getNativeType(NULL_TYPE);
}
public JSType caseNumberType() {
return getNativeType(NUMBER_TYPE);
}
public JSType caseObjectType(ObjectType type) {
return type;
}
public JSType caseStringType() {
return getNativeType(STRING_TYPE);
}
public JSType caseVoidType() {
return getNativeType(VOID_TYPE);
}
}
/**
* @see ChainableReverseAbstractInterpreter#getRestrictedByTypeOfResult
*/
private class RestrictByOneTypeOfResultVisitor
extends RestrictByTypeOfResultVisitor {
/**
* A value known to be equal or not equal to the result of the
* {@code typeOf} operation.
*/
private final String value;
/**
* {@code true} if the {@code typeOf} result is known to equal
* {@code value}; {@code false} if it is known <em>not</em> to equal
* {@code value}.
*/
private final boolean resultEqualsValue;
RestrictByOneTypeOfResultVisitor(String value, boolean resultEqualsValue) {
this.value = value;
this.resultEqualsValue = resultEqualsValue;
}
/**
* Computes whether the given result of a {@code typeof} operator matches
* expectations, i.e. whether a type that gives such a result should be
* kept.
*/
private boolean matchesExpectation(String result) {
return result.equals(value) == resultEqualsValue;
}
@Override
protected JSType caseTopType
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>(JSType topType) {
JSType result = topType;
if (resultEqualsValue) {
JSType typeByName = getNativeTypeForTypeOf(value);
if (typeByName != null) {
result = typeByName;
}
}
return result;
}
public JSType caseNoObjectType() {
return (value.equals("object") || value.equals("function")) ==
resultEqualsValue ? getNativeType(NO_OBJECT_TYPE) : null;
}
public JSType caseBooleanType() {
return matchesExpectation("boolean") ? getNativeType(BOOLEAN_TYPE) : null;
}
public JSType caseFunctionType(FunctionType type) {
return matchesExpectation("function") ? type : null;
}
public JSType caseNullType() {
return matchesExpectation("object") ? getNativeType(NULL_TYPE) : null;
}
public JSType caseNumberType() {
return matchesExpectation("number") ? getNativeType(NUMBER_TYPE) : null;
}
public JSType caseObjectType(ObjectType type) {
if (value.equals("function")) {
JSType ctorType = getNativeType(U2U_CONSTRUCTOR_TYPE);
return resultEqualsValue && ctorType.isSubtype(type) ? ctorType : null;
}
return matchesExpectation("object") ? type : null;
}
public JSType caseStringType() {
return matchesExpectation("string") ? getNativeType(STRING_TYPE) : null;
}
public JSType caseVoidType() {
return matchesExpectation("undefined") ? getNativeType(VOID_TYPE) : null;
}
}
/**
* Returns a version of type where undefined is not present.
*/
final JSType getRestrictedWithoutUndefined(JSType type) {
return type == null ? null : type.visit(restrictUndefinedVisitor);
}
/**
* Returns a version of type where null is not present.
*/
final JSType getRestrictedWithoutNull(JSType type) {
return type == null ? null : type.visit(restrictNullVisitor);
}
/**
* Returns a version of {@code type} that is restricted by some knowledge
* about the result of the {@code typeof} operation.
* <p>
* The behavior of the {@code typeof} operator can be summarized
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> by the
* following table:
* <table>
* <tr><th>type</th><th>result</th></tr>
* <tr><td>{@code undefined}</td><td>"undefined"</td></tr>
* <tr><td>{@code null}</td><td>"object"</td></tr>
* <tr><td>{@code boolean}</td><td>"boolean"</td></tr>
* <tr><td>{@code number}</td><td>"number"</td></tr>
* <tr><td>{@code string}</td><td>"string"</td></tr>
* <tr><td>{@code Object} (which doesn't implement [[Call]])</td>
* <td>"object"</td></tr>
* <tr><td>{@code Object} (which implements [[Call]])</td>
* <td>"function"</td></tr>
* </table>
* @param type the type to restrict
* @param value A value known to be equal or not equal to the result of the
* {@code typeof} operation
* @param resultEqualsValue {@code true} if the {@code typeOf} result is known
* to equal {@code value}; {@code false} if it is known <em>not</em> to
* equal {@code value}
* @return the restricted type or null if no version of the type matches the
* restriction
*/
JSType getRestrictedByTypeOfResult(JSType type, String value,
boolean resultEqualsValue) {
if (type == null) {
if (resultEqualsValue) {
JSType result = getNativeTypeForTypeOf(value);
return result == null ? getNativeType(UNKNOWN_TYPE) : result;
} else {
return null;
}
}
return type.visit(
new RestrictByOneTypeOfResultVisitor(value, resultEqualsValue));
}
JSType getNativeType(JSTypeNative typeId) {
return typeRegistry.getNativeType(typeId);
}
/**
* If we definitely know what a type is based on the typeof result,
* return it. Otherwise, return null.
*
* The typeof operation in JS is poorly defined, and this function works
* for both the native typeof and goog.typeOf. It should not be
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> outerThis = this;
final Scope outerScope = t.getScope();
final FunctionType functionType = (FunctionType) n.getJSType();
final String functionPrivateName = n.getFirstChild().getString();
if (functionPrivateName != null && functionPrivateName.length() > 0 &&
outerScope.isDeclared(functionPrivateName, false) &&
// Ideally, we would want to check whether the type in the scope
// differs from the type being defined, but then the extern
// redeclarations of built-in types generates spurious warnings.
!(outerScope.getVar(
functionPrivateName).getType() instanceof FunctionType)) {
report(t, n, FUNCTION_MASKS_VARIABLE, functionPrivateName);
}
// TODO(user): Only traverse the function's body. The function's
// name and arguments are traversed by the scope creator, and ideally
// should not be traversed by the type checker.
break;
}
return true;
}
/**
* This is the meat of the type checking. It is basically one big switch,
* with each case representing one type of parse tree node. The individual
* cases are usually pretty straightforward.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
* @param parent The parent of the node n.
*/
public void visit(NodeTraversal t, Node n, Node parent) {
JSType childType;
JSType leftType, rightType;
Node left, right;
// To be explicitly set to false if the node is not typeable.
boolean typeable = true;
switch (n.getType()) {
case Token.NAME:
typeable = visitName(t, n, parent);
break;
case Token.LP:
// If this is under a FUNCTION node, it is a parameter list and can be
// ignored here.
if (parent.getType() != Token.FUNCTION) {
ensureTyped(t, n, getJSType(n.getFirstChild()));
} else {
typeable = false;
}
break;
case Token.COMMA:
ensureTyped(t, n, getJSType(n.getLastChild()));
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> getJSType(left), "increment/decrement");
ensureTyped(t, n, NUMBER_TYPE);
break;
case Token.NOT:
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.VOID:
ensureTyped(t, n, VOID_TYPE);
break;
case Token.TYPEOF:
ensureTyped(t, n, STRING_TYPE);
break;
case Token.BITNOT:
childType = getJSType(n.getFirstChild());
if (!childType.matchesInt32Context()) {
report(t, n, BIT_OPERATION, NodeUtil.opToStr(n.getType()),
childType.toString());
}
ensureTyped(t, n, NUMBER_TYPE);
break;
case Token.POS:
case Token.NEG:
left = n.getFirstChild();
validator.expectNumber(t, left, getJSType(left), "sign operator");
ensureTyped(t, n, NUMBER_TYPE);
break;
case Token.EQ:
case Token.NE: {
leftType = getJSType(n.getFirstChild());
rightType = getJSType(n.getLastChild());
JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined();
JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined();
TernaryValue result =
leftTypeRestricted.testForEquality(rightTypeRestricted);
if (result != TernaryValue.UNKNOWN) {
if (n.getType() == Token.NE) {
result = result.not();
}
report(t, n, DETERMINISTIC_TEST, leftType.toString(),
rightType.toString(), result.toString());
}
ensureTyped(t, n, BOOLEAN_TYPE);
break;
}
case Token.SHEQ:
case Token.SHNE: {
leftType = getJSType(n.getFirstChild());
rightType = getJSType(n.getLastChild());
JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined();
JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined();
if (!leftTypeRestricted.canTestForShallowEqualityWith(
rightTypeRestricted)) {
report(t, n, DETERMINISTIC_TEST_NO_RESULT, leftType
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
/**
* A factory for creating JSCompiler passes based on the Options
* injected. Contains all meta-data about compiler passes (like
* whether it can be run multiple times, a human-readable name for
* logging, etc.).
*
* @author nicksantos@google.com (Nick Santos)
*/
public abstract class PassFactory {
private final String name;
private final boolean isOneTimePass;
private boolean isCreated = false;
/**
* @param name The name of the pass that this factory creates.
* @param isOneTimePass If true, the pass produced by this factory can
* only be run once.
*/
protected PassFactory(String name, boolean isOneTimePass) {
this.name = name;
this.isOneTimePass = isOneTimePass;
}
/**
* @return The name of this pass.
*/
String getName() {
return name;
}
/**
* @return Whether the pass produced by this factory can only be run once.
*/
boolean isOneTimePass() {
return isOneTimePass;
}
/**
* Make a new pass factory that only creates one-time passes.
*/
PassFactory makeOneTimePass() {
if (isOneTimePass()) {
return this;
}
final PassFactory self = this;
return new PassFactory(name, true /* one time pass */) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return self.createInternal(compiler);
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.Node;
/**
* Look for references to the global RegExp object that would cause
* regular expressions to be unoptimizable.
*
* @author johnlenz@google.com (John Lenz)
*/
class CheckRegExp extends AbstractPostOrderCallback implements CompilerPass {
static final DiagnosticType REGEXP_REFERENCE =
DiagnosticType.warning("JSC_REGEXP_REFERENCE",
"References to the global RegExp object prevents " +
"optimization of regular expressions.");
private final AbstractCompiler compiler;
private boolean globalRegExpPropertiesUsed = false;
public boolean isGlobalRegExpPropertiesUsed() {
return globalRegExpPropertiesUsed;
}
public CheckRegExp(AbstractCompiler compiler) {
this.compiler = compiler;
}
@Override
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (NodeUtil.isReferenceName(n)) {
String name = n.getString();
if (name.equals("RegExp") && t.getScope().getVar(name) == null) {
int parentType = parent.getType();
boolean first = (n == parent.getFirstChild());
if (!((parentType == Token.NEW && first)
|| (parentType == Token.CALL && first)
|| (parentType == Token.INSTANCEOF && !
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.STRING);
}
return ret;
}
@Override
Node processArrayLiteral(ArrayLiteral literalNode) {
if (literalNode.isDestructuring()) {
reportDestructuringAssign(literalNode);
}
Node node = newNode(Token.ARRAYLIT);
int skipCount = 0;
for (AstNode child : literalNode.getElements()) {
Node c = transform(child);
if (c.getType() == Token.EMPTY) {
skipCount++;
}
node.addChildToBack(c);
}
if (skipCount > 0) {
int[] skipIndexes = new int[skipCount];
int i = 0;
int j = 0;
for (Node child : node.children()) {
if (child.getType() == Token.EMPTY) {
node.removeChild(child);
skipIndexes[j] = i;
j++;
}
i++;
}
node.putProp(Node.SKIP_INDEXES_PROP, skipIndexes);
}
return node;
}
@Override
Node processAssignment(Assignment assignmentNode) {
return processInfixExpression(assignmentNode);
}
@Override
Node processAstRoot(AstRoot rootNode) {
Node node = newNode(Token.SCRIPT);
for (com.google.javascript.jscomp.mozilla.rhino.Node child : rootNode) {
node.addChildToBack(transform((AstNode)child));
}
parseDirectives(node);
return node;
}
/**
* Parse the directives, encode them in the AST, and remove their nodes.
*
* For information on ES5 directives, see section 14.1 of
* Ecma-262, Edition 5.
*
* It would be nice if Rhino would eventually take care of this for
* us, but right now their directive-processing is a one-off.
*/
private void parseDirectives(Node node) {
// Remove all the directives, and encode them in the AST.
Set<String> directives = null;
while (isDirective(node.getFirstChild())) {
String directive = node.removeFirstChild().getFirstChild().getString();
if (directives == null) {
directives = Sets.newHashSet(directive);
} else {
directives.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>add(directive);
}
}
if (directives != null) {
node.setDirectives(directives);
}
}
private boolean isDirective(Node n) {
if (n == null) return false;
int nType = n.getType();
return (nType == Token.EXPR_RESULT || nType == Token.EXPR_VOID) &&
n.getFirstChild().getType() == Token.STRING &&
ALLOWED_DIRECTIVES.contains(n.getFirstChild().getString());
}
@Override
Node processBlock(Block blockNode) {
return processGeneric(blockNode);
}
@Override
Node processBreakStatement(BreakStatement statementNode) {
Node node = newNode(Token.BREAK);
if (statementNode.getBreakLabel() != null) {
Node labelName = transform(statementNode.getBreakLabel());
// Change the NAME to LABEL_NAME
labelName.setType(Token.LABEL_NAME);
node.addChildToBack(labelName);
}
return node;
}
@Override
Node processCatchClause(CatchClause clauseNode) {
AstNode catchVar = clauseNode.getVarName();
Node node = newNode(Token.CATCH, transform(catchVar));
if (clauseNode.getCatchCondition() != null) {
node.addChildToBack(transform(clauseNode.getCatchCondition()));
} else {
Node catchCondition = newNode(Token.EMPTY);
// Old Rhino used the position of the catchVar as the position
// for the (nonexistent) error being caught.
catchCondition.setLineno(catchVar.getLineno());
int clauseAbsolutePosition =
position2charno(catchVar.getAbsolutePosition());
catchCondition.setCharno(clauseAbsolutePosition);
node.addChildToBack(catchCondition);
}
node.addChildToBack(transformBlock(clauseNode.getBody()));
return node;
}
@Override
Node processConditionalExpression(ConditionalExpression exprNode) {
return newNode(
Token.HOOK,
transform(exprNode.getTestExpression()),
transform(exprNode.getTrueExpression()),
transform(exprNode.getFalseExpression()));
}
@Override
Node processContinueStatement(ContinueStatement statementNode) {
Node node = newNode(Token.CONTINUE);
if (statementNode.getLabel() !=
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> null) {
Node labelName = transform(statementNode.getLabel());
// Change the NAME to LABEL_NAME
labelName.setType(Token.LABEL_NAME);
node.addChildToBack(labelName);
}
return node;
}
@Override
Node processDoLoop(DoLoop loopNode) {
return newNode(
Token.DO,
transformBlock(loopNode.getBody()),
transform(loopNode.getCondition()));
}
@Override
Node processElementGet(ElementGet getNode) {
return newNode(
Token.GETELEM,
transform(getNode.getTarget()),
transform(getNode.getElement()));
}
@Override
Node processEmptyExpression(EmptyExpression exprNode) {
Node node = newNode(Token.EMPTY);
return node;
}
@Override
Node processExpressionStatement(ExpressionStatement statementNode) {
Node node = newNode(transformTokenType(statementNode.getType()));
node.addChildToBack(transform(statementNode.getExpression()));
return node;
}
@Override
Node processForInLoop(ForInLoop loopNode) {
return newNode(
Token.FOR,
transform(loopNode.getIterator()),
transform(loopNode.getIteratedObject()),
transformBlock(loopNode.getBody()));
}
@Override
Node processForLoop(ForLoop loopNode) {
Node node = newNode(
Token.FOR,
transform(loopNode.getInitializer()),
transform(loopNode.getCondition()),
transform(loopNode.getIncrement()));
node.addChildToBack(transformBlock(loopNode.getBody()));
return node;
}
@Override
Node processFunctionCall(FunctionCall callNode) {
Node node = newNode(transformTokenType(callNode.getType()),
transform(callNode.getTarget()));
for (AstNode child : callNode.getArguments()) {
node.addChildToBack(transform(child));
}
int leftParamPos = callNode.getAbsolutePosition() + callNode.getLp();
node.setLineno(callNode.getLineno());
node.setCharno(position2charno(leftParamPos));
return node;
}
@Override
Node processFunctionNode(FunctionNode functionNode) {
Name name = functionNode.getFunctionName();
Boolean isUnnamedFunction = false;
if (name == null
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>) {
name = new Name();
name.setIdentifier("");
isUnnamedFunction = true;
}
Node node = newNode(Token.FUNCTION);
node.putProp(Node.SOURCENAME_PROP, functionNode.getSourceName());
Node newName = transform(name);
if (isUnnamedFunction) {
// Old Rhino tagged the empty name node with the line number of the
// declaration.
newName.setLineno(functionNode.getLineno());
// TODO(bowdidge) Mark line number of paren correctly.
// Same problem as below - the left paren might not be on the
// same line as the function keyword.
int lpColumn = functionNode.getAbsolutePosition() +
functionNode.getLp();
newName.setCharno(position2charno(lpColumn));
}
node.addChildToBack(newName);
Node lp = newNode(Token.LP);
// The left paren's complicated because it's not represented by an
// AstNode, so there's nothing that has the actual line number that it
// appeared on. We know the paren has to appear on the same line as the
// function name (or else a semicolon will be inserted.) If there's no
// function name, assume the paren was on the same line as the function.
// TODO(bowdidge): Mark line number of paren correctly.
Name fnName = functionNode.getFunctionName();
if (fnName != null) {
lp.setLineno(fnName.getLineno());
} else {
lp.setLineno(functionNode.getLineno());
}
int lparenCharno = functionNode.getLp() +
functionNode.getAbsolutePosition();
lp.setCharno(position2charno(lparenCharno));
for (AstNode param : functionNode.getParams()) {
lp.addChildToBack(transform(param));
}
node.addChildToBack(lp);
Node bodyNode = transform(functionNode.getBody());
parseDirectives(bodyNode);
node.addChildToBack(bodyNode);
return node;
}
@Override
Node processIfStatement(IfStatement statementNode) {
Node node = newNode(Token.IF);
node.addChildToBack(transform(statementNode.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>getCondition()));
node.addChildToBack(transformBlock(statementNode.getThenPart()));
if (statementNode.getElsePart() != null) {
node.addChildToBack(transformBlock(statementNode.getElsePart()));
}
return node;
}
@Override
Node processInfixExpression(InfixExpression exprNode) {
Node n = newNode(
transformTokenType(exprNode.getType()),
transform(exprNode.getLeft()),
transform(exprNode.getRight()));
// Set the line number here so we can fine-tune it in ways transform
// doesn't do.
n.setLineno(exprNode.getLineno());
// Position in new ASTNode is to start of expression, but old-fashioned
// line numbers from Node reference the operator token. Add the offset
// to the operator to get the correct character number.
n.setCharno(position2charno(exprNode.getAbsolutePosition() +
exprNode.getOperatorPosition()));
return n;
}
@Override
Node processKeywordLiteral(KeywordLiteral literalNode) {
return newNode(transformTokenType(literalNode.getType()));
}
@Override
Node processLabel(Label labelNode) {
return newStringNode(Token.LABEL_NAME, labelNode.getName());
}
@Override
Node processLabeledStatement(LabeledStatement statementNode) {
Node node = newNode(Token.LABEL);
Node prev = null;
Node cur = node;
for (Label label : statementNode.getLabels()) {
if (prev != null) {
prev.addChildToBack(cur);
}
cur.addChildToBack(transform(label));
cur.setLineno(label.getLineno());
int clauseAbsolutePosition =
position2charno(label.getAbsolutePosition());
cur.setCharno(clauseAbsolutePosition);
prev = cur;
cur = newNode(Token.LABEL);
}
prev.addChildToBack(transform(statementNode.getStatement()));
return node;
}
@Override
Node processName(Name nameNode) {
return newStringNode(Token.NAME, nameNode.getIdentifier());
}
@Override
Node processNewExpression(NewExpression exprNode) {
return processFunctionCall(exprNode);
}
@Override
Node process
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>NumberLiteral(NumberLiteral literalNode) {
return newNumberNode(literalNode.getNumber());
}
@Override
Node processObjectLiteral(ObjectLiteral literalNode) {
if (literalNode.isDestructuring()) {
reportDestructuringAssign(literalNode);
}
Node node = newNode(Token.OBJECTLIT);
for (ObjectProperty el : literalNode.getElements()) {
if (el.isGetter()) {
reportGetter(el);
} else if (el.isSetter()) {
reportSetter(el);
} else {
node.addChildToBack(transformAsString(el.getLeft()));
node.addChildToBack(transform(el.getRight()));
}
}
return node;
}
@Override
Node processObjectProperty(ObjectProperty propertyNode) {
return processInfixExpression(propertyNode);
}
@Override
Node processParenthesizedExpression(ParenthesizedExpression exprNode) {
Node node = transform(exprNode.getExpression());
node.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE);
return node;
}
@Override
Node processPropertyGet(PropertyGet getNode) {
return newNode(
Token.GETPROP,
transform(getNode.getTarget()),
transformAsString(getNode.getProperty()));
}
@Override
Node processRegExpLiteral(RegExpLiteral literalNode) {
Node literalStringNode = newStringNode(literalNode.getValue());
// assume it's on the same line.
literalStringNode.setLineno(literalNode.getLineno());
Node node = newNode(Token.REGEXP, literalStringNode);
String flags = literalNode.getFlags();
if (flags != null && !flags.isEmpty()) {
Node flagsNode = newStringNode(flags);
// Assume the flags are on the same line as the literal node.
flagsNode.setLineno(literalNode.getLineno());
node.addChildToBack(flagsNode);
}
return node;
}
@Override
Node processReturnStatement(ReturnStatement statementNode) {
Node node = newNode(Token.RETURN);
if (statementNode.getReturnValue() != null) {
node.addChildToBack(transform(statementNode.getReturnValue()));
}
return node;
}
@Override
Node processScope(Scope scopeNode) {
return
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> processGeneric(scopeNode);
}
@Override
Node processStringLiteral(StringLiteral literalNode) {
Node n = newStringNode(literalNode.getValue());
return n;
}
@Override
Node processSwitchCase(SwitchCase caseNode) {
Node node;
if (caseNode.isDefault()) {
node = newNode(Token.DEFAULT);
} else {
AstNode expr = caseNode.getExpression();
node = newNode(Token.CASE, transform(expr));
}
Node block = newNode(Token.BLOCK);
block.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true);
block.setLineno(caseNode.getLineno());
block.setCharno(position2charno(caseNode.getAbsolutePosition()));
if (caseNode.getStatements() != null) {
for (AstNode child : caseNode.getStatements()) {
block.addChildToBack(transform(child));
}
}
node.addChildToBack(block);
return node;
}
@Override
Node processSwitchStatement(SwitchStatement statementNode) {
Node node = newNode(Token.SWITCH,
transform(statementNode.getExpression()));
for (AstNode child : statementNode.getCases()) {
node.addChildToBack(transform(child));
}
return node;
}
@Override
Node processThrowStatement(ThrowStatement statementNode) {
return newNode(Token.THROW,
transform(statementNode.getExpression()));
}
@Override
Node processTryStatement(TryStatement statementNode) {
Node node = newNode(Token.TRY,
transformBlock(statementNode.getTryBlock()));
Node block = newNode(Token.BLOCK);
boolean lineSet = false;
for (CatchClause cc : statementNode.getCatchClauses()) {
// Mark the enclosing block at the same line as the first catch
// clause.
if (lineSet == false) {
block.setLineno(cc.getLineno());
lineSet = true;
}
block.addChildToBack(transform(cc));
}
node.addChildToBack(block);
AstNode finallyBlock = statementNode.getFinallyBlock();
if (finallyBlock != null) {
node.addChildToBack(transformBlock(finallyBlock));
}
// If
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> we didn't set the line on the catch clause, then
// we've got an empty catch clause. Set its line to be the same
// as the finally block (to match Old Rhino's behavior.)
if ((lineSet == false) && (finallyBlock != null)) {
block.setLineno(finallyBlock.getLineno());
}
return node;
}
@Override
Node processUnaryExpression(UnaryExpression exprNode) {
int type = transformTokenType(exprNode.getType());
Node operand = transform(exprNode.getOperand());
if (type == Token.NEG && operand.getType() == Token.NUMBER) {
operand.setDouble(-operand.getDouble());
return operand;
} else {
Node node = newNode(type, operand);
if (exprNode.isPostfix()) {
node.putBooleanProp(Node.INCRDECR_PROP, true);
}
return node;
}
}
@Override
Node processVariableDeclaration(VariableDeclaration declarationNode) {
Node node = newNode(Token.VAR);
for (VariableInitializer child : declarationNode.getVariables()) {
node.addChildToBack(transform(child));
}
return node;
}
@Override
Node processVariableInitializer(VariableInitializer initializerNode) {
Node node = transform(initializerNode.getTarget());
if (initializerNode.getInitializer() != null) {
node.addChildToBack(transform(initializerNode.getInitializer()));
node.setLineno(node.getLineno());
}
return node;
}
@Override
Node processWhileLoop(WhileLoop loopNode) {
return newNode(
Token.WHILE,
transform(loopNode.getCondition()),
transformBlock(loopNode.getBody()));
}
@Override
Node processWithStatement(WithStatement statementNode) {
return newNode(
Token.WITH,
transform(statementNode.getExpression()),
transformBlock(statementNode.getStatement()));
}
@Override
Node processIllegalToken(AstNode node) {
errorReporter.error(
"Unsupported syntax: " +
com.google.javascript.jscomp.mozilla.rhino.Token.typeToName(
node.getType()),
sourceName,
node.getLineno(), "", 0);
return newNode(Token.EMPTY);
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> case com.google.javascript.jscomp.mozilla.rhino.Token.VOID:
return Token.VOID;
case com.google.javascript.jscomp.mozilla.rhino.Token.RESERVED:
return Token.RESERVED;
case com.google.javascript.jscomp.mozilla.rhino.Token.EMPTY:
return Token.EMPTY;
case com.google.javascript.jscomp.mozilla.rhino.Token.BLOCK:
return Token.BLOCK;
case com.google.javascript.jscomp.mozilla.rhino.Token.LABEL:
return Token.LABEL;
case com.google.javascript.jscomp.mozilla.rhino.Token.TARGET:
return Token.TARGET;
case com.google.javascript.jscomp.mozilla.rhino.Token.LOOP:
return Token.LOOP;
case com.google.javascript.jscomp.mozilla.rhino.Token.EXPR_VOID:
case com.google.javascript.jscomp.mozilla.rhino.Token.EXPR_RESULT:
return Token.EXPR_RESULT;
case com.google.javascript.jscomp.mozilla.rhino.Token.JSR:
return Token.JSR;
case com.google.javascript.jscomp.mozilla.rhino.Token.SCRIPT:
return Token.SCRIPT;
case com.google.javascript.jscomp.mozilla.rhino.Token.TYPEOFNAME:
return Token.TYPEOFNAME;
case com.google.javascript.jscomp.mozilla.rhino.Token.USE_STACK:
return Token.USE_STACK;
case com.google.javascript.jscomp.mozilla.rhino.Token.SETPROP_OP:
return Token.SETPROP_OP;
case com.google.javascript.jscomp.mozilla.rhino.Token.SETELEM_OP:
return Token.SETELEM_OP;
case com.google.javascript.jscomp.mozilla.rhino.Token.LOCAL_BLOCK:
return Token.LOCAL_BLOCK;
case com.google.javascript.jscomp.mozilla.rhino.Token.SET_REF_OP:
return Token.SET_REF_OP;
case com.google.javascript.jscomp.mozilla.rhino.Token.DOTDOT:
return Token.DOTDOT;
case com.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import com.google.javascript.rhino.ErrorReporter;
/**
* Value types (null, void, number, boolean, string).
*/
abstract class ValueType extends JSType {
ValueType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isSubtype(JSType that) {
return JSType.isSubtype(this, that);
}
@Override
final JS
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.CheckLevel;
/**
* Sets the level for a particular DiagnosticGroup.
* @author nicksantos@google.com (Nick Santos)
*/
public class DiagnosticGroupWarningsGuard extends WarningsGuard {
private final DiagnosticGroup group;
private final CheckLevel level;
public DiagnosticGroupWarningsGuard(
DiagnosticGroup group, CheckLevel level) {
this.group = group;
this.level = level;
}
@Override
public CheckLevel level(JSError error) {
return group.matches(error) ? level : null;
}
@Override
public boolean disables(DiagnosticGroup otherGroup) {
return !level.isOn() && group.isSubGroup(otherGroup);
}
@Override
public boolean enables(DiagnosticGroup otherGroup) {
if (level.isOn()) {
for (DiagnosticType type : otherGroup.getTypes()) {
if (group.matches(type)) {
return true;
}
}
}
return false;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
/**
* Annotates nodes with information from their original input file
* before the compiler performs work that changes this information (such
* as its original location, its original name, etc).
*
* Information saved:
*
* - Annotates all nodes with a SOURCEFILE_PROP indicating the input
* file from which it was generated.
*
* - Annotates all NAME nodes with an ORIGINALNAME_PROP indicating its original
* name.
*
* - Annotates all string GET_PROP nodes with an ORIGINALNAME_PROP.
*
* - Annotates all OBJECT_LITERAL unquoted string key nodes with an
* ORIGINALNAME_PROP.
*
*
*/
class SourceInformationAnnotator extends
NodeTraversal.AbstractPostOrderCallback {
private final String sourceFile;
private final boolean doSanityChecks;
public SourceInformationAnnotator(
String sourceFile, boolean doSanityChecks) {
this.sourceFile = sourceFile;
this.doSanityChecks = doSanityChecks;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
// Verify the source file is annotated.
if (doSanityChecks && sourceFile != null) {
Preconditions.checkState(sourceFile.equals(
n.getProp(Node.SOURCEFILE_PROP)));
}
// Annotate the original name.
switch (n.getType
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> roots) {
Preconditions.checkArgument(inputs.containsAll(roots));
Set<INPUT> included = Sets.newHashSet();
Deque<INPUT> worklist = new ArrayDeque<INPUT>(roots);
while (!worklist.isEmpty()) {
INPUT current = worklist.pop();
if (included.add(current)) {
for (String req : current.getRequires()) {
INPUT dep = provideMap.get(req);
if (dep != null) {
worklist.add(dep);
}
}
}
}
ImmutableList.Builder<INPUT> builder = ImmutableList.builder();
for (INPUT current : sortedList) {
if (included.contains(current)) {
builder.add(current);
}
}
return builder.build();
}
public List<INPUT> getInputsWithoutProvides() {
return Collections.<INPUT>unmodifiableList(noProvides);
}
private static <T> List<T> topologicalStableSort(
List<T> items, Multimap<T, T> deps) {
final Map<T, Integer> originalIndex = Maps.newHashMap();
for (int i = 0; i < items.size(); i++) {
originalIndex.put(items.get(i), i);
}
PriorityQueue<T> inDegreeZero = new PriorityQueue<T>(items.size(),
new Comparator<T>() {
@Override
public int compare(T a, T b) {
return originalIndex.get(a).intValue() -
originalIndex.get(b).intValue();
}
});
List<T> result = Lists.newArrayList();
Multiset<T> inDegree = HashMultiset.create();
Multimap<T, T> reverseDeps = ArrayListMultimap.create();
Multimaps.invertFrom(deps, reverseDeps);
// First, add all the inputs with in-degree 0.
for (T item : items) {
Collection<T> itemDeps = deps.get(item);
inDegree.add(item, itemDeps.size());
if (itemDeps.isEmpty()) {
inDegreeZero.add(item);
}
}
// Then, iterate to a fixed point over the reverse dependency graph.
while (!inDegreeZero.isEmpty()) {
T item = inDegreeZero
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Prototype;
} else if (implicitPrototype == null) {
this.implicitPrototype =
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
} else {
this.implicitPrototype = implicitPrototype;
}
}
/**
* Gets the number of properties of this object.
*/
@Override
public int getPropertiesCount() {
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype == null) {
return this.properties.size();
}
int localCount = 0;
for (String property : properties.keySet()) {
if (!implicitPrototype.hasProperty(property)) {
localCount++;
}
}
return implicitPrototype.getPropertiesCount() + localCount;
}
@Override
public boolean hasProperty(String propertyName) {
if (properties.get(propertyName) != null) {
return true;
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.hasProperty(propertyName);
}
return false;
}
@Override
public boolean hasOwnProperty(String propertyName) {
return properties.get(propertyName) != null;
}
@Override
public Set<String> getOwnPropertyNames() {
return properties.keySet();
}
@Override
public boolean isPropertyTypeDeclared(String property) {
Property p = properties.get(property);
if (p == null) {
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyTypeDeclared(property);
}
// property does not exist
return false;
}
return !p.inferred;
}
@Override
void collectPropertyNames(Set<String> props) {
for (String prop : properties.keySet()) {
props.add(prop);
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
implicitPrototype.collectPropertyNames(props);
}
}
@Override
public boolean isPropertyTypeInferred(String property) {
Property p = properties.get(property);
if (p == null) {
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyTypeInferred(property);
}
// property does not exist
return false;
}
return p.in
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>ferred;
}
@Override
public JSType getPropertyType(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.type;
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.getPropertyType(propertyName);
}
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
@Override
public boolean isPropertyInExterns(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.inExterns;
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyInExterns(propertyName);
}
return false;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
boolean inExterns) {
if (hasOwnDeclaredProperty(name)) {
return false;
}
properties.put(name, new Property(type, inferred, inExterns));
return true;
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.docInfo;
}
return null;
}
@Override
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
if (info != null) {
if (!properties.containsKey(propertyName)) {
// If docInfo was attached, but the type of the property
// was not defined anywhere, then we consider this an explicit
// declaration of the property.
defineInferredProperty(propertyName, getPropertyType(propertyName),
inExterns);
}
// The prototype property is not represented as a normal Property.
// We probably don't want to attach any JSDoc to it anyway.
Property property = properties.get(propertyName);
if (property != null) {
property.docInfo = info;
}
}
}
@Override
public boolean matchesNumberContext() {
return isNumberObjectType() || isDateType() || isBooleanObjectType() ||
isStringObjectType() || hasOverridenNativeProperty("valueOf");
}
@
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Override
public boolean matchesStringContext() {
return isTheObjectType() || isStringObjectType() || isDateType() ||
isRegexpType() || isArrayType() || isNumberObjectType() ||
isBooleanObjectType() || hasOverridenNativeProperty("toString");
}
/**
* Given the name of a native object property, checks whether the property is
* present on the object and different from the native one.
*/
private boolean hasOverridenNativeProperty(String propertyName) {
if (isNative()) {
return false;
}
JSType propertyType = getPropertyType(propertyName);
ObjectType nativeType =
this.isFunctionType() ?
registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE) :
registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE);
JSType nativePropertyType = nativeType.getPropertyType(propertyName);
return propertyType != nativePropertyType;
}
@Override
public JSType unboxesTo() {
if (isStringObjectType()) {
return getNativeType(JSTypeNative.STRING_TYPE);
} else if (isBooleanObjectType()) {
return getNativeType(JSTypeNative.BOOLEAN_TYPE);
} else if (isNumberObjectType()) {
return getNativeType(JSTypeNative.NUMBER_TYPE);
} else {
return super.unboxesTo();
}
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean canBeCalled() {
return isRegexpType();
}
/**
* Whether this represents a native type (such as Object, Date,
* RegExp, etc.).
*/
boolean isNative() {
return nativeType;
}
@Override
public String toString() {
if (hasReferenceName()) {
return getReferenceName();
} else if (prettyPrint) {
// Use a tree set so that the properties are sorted.
Set<String> propertyNames = Sets.newTreeSet();
for (ObjectType current = this;
current != null && !current.isNativeObjectType() &&
propertyNames.size() <= MAX_PRETTY_PRINTED_PROPERTIES;
current = current.getImplicitPrototype()) {
propertyNames.addAll(current.getOwnPropertyNames());
}
StringBuilder sb = new StringBuilder();
sb.append("{");
int i = 0
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>;
for (String property : propertyNames) {
if (i > 0) {
sb.append(", ");
}
sb.append(property);
sb.append(": ");
sb.append(getPropertyType(property).toString());
++i;
if (i == MAX_PRETTY_PRINTED_PROPERTIES) {
sb.append(", ...");
break;
}
}
sb.append("}");
return sb.toString();
} else {
return "{...}";
}
}
void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
public ObjectType getImplicitPrototype() {
return implicitPrototype;
}
/**
* This should only be reset on the FunctionPrototypeType, only to fix an
* incorrectly established prototype chain due to the user having a mismatch
* in super class declaration, and only before properties on that type are
* processed.
*/
void setImplicitPrototype(ObjectType implicitPrototype) {
checkState(!hasCachedValues());
this.implicitPrototype = implicitPrototype;
}
@Override
public String getReferenceName() {
if (className != null) {
return className;
} else {
return null;
}
}
@Override
public boolean hasReferenceName() {
return className != null;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
}
// Union types
if (that instanceof UnionType) {
// The static {@code JSType.isSubtype} check already decomposed
// union types, so we don't need to check those again.
return false;
}
// record types
if (that instanceof RecordType) {
return RecordType.isSubtype(this, (RecordType) that);
}
// Interfaces
// Find all the interfaces implemented by this class and compare each one
// to the interface instance.
ObjectType thatObj = that.toObjectType();
ObjectType thatCtor = thatObj == null ? null : thatObj.getConstructor();
if (thatCtor != null && thatCtor.isInterface()) {
Iterable<ObjectType> thisInterfaces = getCtorImplementedInterfaces();
for (ObjectType thisInterface : this
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Interfaces) {
if (thisInterface.isSubtype(that)) {
return true;
}
}
}
// other prototype based objects
if (that != null) {
if (isUnknownType() || implicitPrototypeChainIsUnknown()) {
// If unsure, say 'yes', to avoid spurious warnings.
// TODO(user): resolve the prototype chain completely in all cases,
// to avoid guessing.
return true;
}
return this.isImplicitPrototype(thatObj);
}
return false;
}
private boolean implicitPrototypeChainIsUnknown() {
ObjectType p = getImplicitPrototype();
while (p != null) {
if (p.isUnknownType()) {
return true;
}
p = p.getImplicitPrototype();
}
return false;
}
private static final class Property implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Property's type.
*/
private JSType type;
/**
* Whether the property's type is inferred.
*/
private final boolean inferred;
/**
* Whether the property is defined in the externs.
*/
private final boolean inExterns;
/** The JSDocInfo for this property. */
private JSDocInfo docInfo = null;
private Property(JSType type, boolean inferred, boolean inExterns) {
this.type = type;
this.inferred = inferred;
this.inExterns = inExterns;
}
}
@Override
public boolean hasCachedValues() {
return super.hasCachedValues();
}
/** Whether this is a built-in object. */
@Override
public boolean isNativeObjectType() {
return nativeType;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this);
// Don't try to resolve native types, because it's unnecessary and
// there are infinite loops between native types.
if (implicitPrototype != null && !implicitPrototype.isNativeObjectType()) {
implicitPrototype = (ObjectType) implicitPrototype.resolve(t, scope);
}
for (Property prop : properties.values()) {
prop.type = safeResolve(prop.type, t, scope);
}
return this;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> wanted since he or she probably meant to use their
// own PassConfig object.
Preconditions.checkNotNull(passes);
if (this.passes != null) {
throw new IllegalStateException("this.passes has already been assigned");
}
this.passes = passes;
}
/**
* Carry out any special checks or procedures that need to be done before
* proceeding with rest of the compilation process.
*
* @return true, to continue with compilation
*/
boolean precheck() {
return true;
}
public void check() {
runCustomPasses(CustomPassExecutionTime.BEFORE_CHECKS);
PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker);
if (options.devMode == DevMode.EVERY_PASS) {
phaseOptimizer.setSanityCheck(sanityCheck);
}
phaseOptimizer.consume(getPassConfig().getChecks());
phaseOptimizer.process(externsRoot, jsRoot);
if (hasErrors()) {
return;
}
// TODO(nicksantos): clean this up. The flow here is too hard to follow.
if (options.nameAnonymousFunctionsOnly) {
return;
}
if (options.removeTryCatchFinally) {
removeTryCatchFinally();
}
if (!options.stripTypes.isEmpty() ||
!options.stripNameSuffixes.isEmpty() ||
!options.stripTypePrefixes.isEmpty() ||
!options.stripNamePrefixes.isEmpty()) {
stripCode(options.stripTypes, options.stripNameSuffixes,
options.stripTypePrefixes, options.stripNamePrefixes);
}
runCustomPasses(CustomPassExecutionTime.BEFORE_OPTIMIZATIONS);
}
private void externExports() {
logger.info("Creating extern file for exports");
startPass("externExports");
ExternExportsPass pass = new ExternExportsPass(this);
process(pass);
externExports = pass.getGeneratedExterns();
endPass();
}
void process(CompilerPass p) {
p.process(externsRoot, jsRoot);
}
private final PassFactory sanityCheck =
new PassFactory("sanityCheck", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new SanityCheck(compiler);
}
};
private void maybeSan
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
currentTracer = null;
maybeSanityCheck();
}
/**
* Returns a new tracer for the given pass name.
*/
Tracer newTracer(String passName) {
String comment = passName
+ (recentChange.hasCodeChanged() ? " on recently changed AST" : "");
if (options.tracer.isOn()) {
tracker.recordPassStart(passName);
}
return new Tracer("Compiler", comment);
}
void stopTracer(Tracer t, String passName) {
long result = t.stop();
if (options.tracer.isOn()) {
tracker.recordPassStop(passName, result);
}
}
/**
* Returns the result of the compilation.
*/
public Result getResult() {
PassConfig.State state = getPassConfig().getIntermediateState();
return new Result(getErrors(), getWarnings(), debugLog.toString(),
state.variableMap, state.propertyMap,
state.anonymousFunctionNameMap, state.stringMap, functionInformationMap,
sourceMap, externExports, state.cssNames);
}
/**
* Returns an array constructed from errors + temporary warnings.
*/
public JSError[] getMessages() {
return getErrors();
}
/**
* Returns the array of errors (never null).
*/
public JSError[] getErrors() {
return errorManager.getErrors();
}
/**
* Returns the array of warnings (never null).
*/
public JSError[] getWarnings() {
return errorManager.getWarnings();
}
/**
* Returns the root node of the AST, which includes both externs and source.
*/
public Node getRoot() {
return externAndJsRoot;
}
/**
* Creates a new id for making unique names.
*/
private int nextUniqueNameId() {
return uniqueNameId++;
}
/**
* Resets the unique name id counter
*/
@VisibleForTesting
void resetUniqueNameId() {
uniqueNameId = 0;
}
@Override
Supplier<String> getUniqueNameIdSupplier() {
final Compiler self = this;
return new Supplier<String>() {
public String get() {
return String.valueOf(self.nextUniqueNameId());
}
};
}
/**
* Set if the normalization
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> pass has been done.
* Note: non-private to enable test cases that require the Normalize pass.
*/
@Override
void setNormalized() {
normalized = true;
}
/**
* Set once unnormalizing passes have been start.
* Note: non-private to enable test cases that require the Normalize pass.
*/
@Override
void setUnnormalized() {
normalized = false;
}
@Override
boolean isNormalized() {
return normalized;
}
@Override
boolean areNodesEqualForInlining(Node n1, Node n2) {
if (options.ambiguateProperties ||
options.disambiguateProperties) {
// The type based optimizations require that type information is preserved
// during other optimizations.
return n1.checkTreeTypeAwareEqualsSilent(n2);
} else {
return n1.checkTreeEqualsSilent(n2);
}
}
//------------------------------------------------------------------------
// Inputs
//------------------------------------------------------------------------
// TODO(nicksantos): Decide which parts of these belong in an AbstractCompiler
// interface, and which ones should always be injected.
@Override
public CompilerInput getInput(String name) {
return inputsByName.get(name);
}
@Override
public CompilerInput newExternInput(String name) {
if (inputsByName.containsKey(name)) {
throw new IllegalArgumentException("Conflicting externs name: " + name);
}
SourceAst ast = new SyntheticAst(name);
CompilerInput input = new CompilerInput(ast, name, true);
inputsByName.put(name, input);
externsRoot.addChildToFront(ast.getAstRoot(this));
return input;
}
/** Add a source input dynamically. Intended for incremental compilation. */
void addIncrementalSourceAst(JsAst ast) {
String sourceName = ast.getSourceFile().getName();
Preconditions.checkState(
getInput(sourceName) == null,
"Duplicate input of name " + sourceName);
inputsByName.put(sourceName, new CompilerInput(ast));
}
@Override
JSModuleGraph getModuleGraph() {
return moduleGraph;
}
@Override
public JSTypeRegistry getTypeRegistry() {
if (typeRegistry == null) {
typeRegistry = new JSTypeRegistry(oldErrorReporter,
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> options.looseTypes);
}
return typeRegistry;
}
@Override
ScopeCreator getScopeCreator() {
return getPassConfig().getScopeCreator();
}
@Override
public Scope getTopScope() {
return getPassConfig().getTopScope();
}
@Override
public ReverseAbstractInterpreter getReverseAbstractInterpreter() {
if (abstractInterpreter == null) {
ChainableReverseAbstractInterpreter interpreter =
new SemanticReverseAbstractInterpreter(
getCodingConvention(), getTypeRegistry());
if (options.closurePass) {
interpreter = new ClosureReverseAbstractInterpreter(
getCodingConvention(), getTypeRegistry())
.append(interpreter).getFirst();
}
abstractInterpreter = interpreter;
}
return abstractInterpreter;
}
@Override
TypeValidator getTypeValidator() {
if (typeValidator == null) {
typeValidator = new TypeValidator(this);
}
return typeValidator;
}
//------------------------------------------------------------------------
// Parsing
//------------------------------------------------------------------------
/**
* Parses the externs and main inputs.
*
* @return A synthetic root node whose two children are the externs root
* and the main root
*/
Node parseInputs() {
boolean devMode = options.devMode != DevMode.OFF;
// If old roots exist (we are parsing a second time), detach each of the
// individual file parse trees.
if (externsRoot != null) {
externsRoot.detachChildren();
}
if (jsRoot != null) {
jsRoot.detachChildren();
}
// Parse main js sources.
jsRoot = new Node(Token.BLOCK);
jsRoot.setIsSyntheticBlock(true);
if (options.tracer.isOn()) {
tracker = new PerformanceTracker(jsRoot,
options.tracer == TracerMode.ALL);
addChangeHandler(tracker.getCodeChangeHandler());
}
Tracer tracer = newTracer("parseInputs");
try {
// Parse externs sources.
externsRoot = new Node(Token.BLOCK);
externsRoot.setIsSyntheticBlock(true);
for (CompilerInput input : externs) {
Node n = input.getAstRoot(this);
if (hasErrors()) {
return null;
}
externsRoot.addChildToBack(n);
}
// Check if the sources need to be re-ordered
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>ate the nodes in the tree with information from the
// input file. This information is used to construct the SourceMap.
SourceInformationAnnotator sia =
new SourceInformationAnnotator(
input.getName(), options.devMode != DevMode.OFF);
NodeTraversal.traverse(this, n, sia);
}
jsRoot.addChildToBack(n);
}
externAndJsRoot = new Node(Token.BLOCK, externsRoot, jsRoot);
externAndJsRoot.setIsSyntheticBlock(true);
return externAndJsRoot;
} finally {
stopTracer(tracer, "parseInputs");
}
}
public Node parse(JSSourceFile file) {
initCompilerOptionsIfTesting();
addToDebugLog("Parsing: " + file.getName());
return new JsAst(file).getAstRoot(this);
}
@Override
Node parseSyntheticCode(String js) {
CompilerInput input = new CompilerInput(
JSSourceFile.fromCode(" [synthetic] ", js));
inputsByName.put(input.getName(), input);
return input.getAstRoot(this);
}
void initCompilerOptionsIfTesting() {
if (options == null) {
// initialization for tests that don't initialize the compiler
// by the normal mechanisms.
initOptions(new CompilerOptions());
}
}
@Override
Node parseSyntheticCode(String fileName, String js) {
initCompilerOptionsIfTesting();
return parse(JSSourceFile.fromCode(fileName, js));
}
Node parseTestCode(String js) {
initCompilerOptionsIfTesting();
CompilerInput input = new CompilerInput(
JSSourceFile.fromCode(" [testcode] ", js));
if (inputsByName == null) {
inputsByName = Maps.newHashMap();
}
inputsByName.put(input.getName(), input);
return input.getAstRoot(this);
}
@Override
ErrorReporter getDefaultErrorReporter() {
return defaultErrorReporter;
}
//------------------------------------------------------------------------
// Convert back to source code
//------------------------------------------------------------------------
/**
* Converts the main parse tree back to js code.
*/
public String toSource() {
return runInCompilerThread(new Callable<String>() {
public String call() throws Exception {
Tracer tracer =
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>\n")
.append(root.getJSDocInfo().getLicense())
.append("*/\n");
}
// If there is a valid source map, then indicate to it that the current
// root node's mappings are offset by the given string builder buffer.
if (options.sourceMapOutputPath != null) {
sourceMap.setStartingPosition(
cb.getLineIndex(), cb.getColumnIndex());
}
String code = toSource(root, sourceMap);
if (!code.isEmpty()) {
cb.append(code);
if (!code.endsWith(";")) {
cb.append(";");
}
}
return null;
}
});
}
/**
* Generates JavaScript source code for an AST, doesn't generate source
* map info.
*/
@Override
String toSource(Node n) {
initCompilerOptionsIfTesting();
return toSource(n, null);
}
/**
* Generates JavaScript source code for an AST.
*/
private String toSource(Node n, SourceMap sourceMap) {
CodePrinter.Builder builder = new CodePrinter.Builder(n);
builder.setPrettyPrint(options.prettyPrint);
builder.setLineBreak(options.lineBreak);
builder.setSourceMap(sourceMap);
builder.setOutputCharset(options.outputCharset);
return builder.build();
}
/**
* Stores a buffer of text to which more can be appended. This is just like a
* StringBuilder except that we also track the number of lines.
*/
public static class CodeBuilder {
private final StringBuilder sb = new StringBuilder();
private int lineCount = 0;
/** Removes all text, but leaves the line count unchanged. */
void reset() {
sb.setLength(0);
}
/** Appends the given string to the text buffer. */
CodeBuilder append(String str) {
sb.append(str);
// Move the line count to the end of the new text.
int index = -1;
while ((index = str.indexOf('\n', index + 1)) >= 0) {
++lineCount;
}
return this;
}
/** Returns all text in the text buffer. */
@Override
public String toString() {
return sb.toString();
}
/** Returns the length of the
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> text buffer. */
public int getLength() {
return sb.length();
}
/** Returns the (zero-based) index of the last line in the text buffer. */
int getLineIndex() {
return lineCount;
}
/** Returns the (zero-based) index of the last column in the text buffer. */
int getColumnIndex() {
int index = sb.lastIndexOf("\n");
return (index >= 0) ? sb.length() - (index + 1) : sb.length();
}
/** Determines whether the text ends with the given suffix. */
boolean endsWith(String suffix) {
return (sb.length() > suffix.length())
&& suffix.equals(sb.substring(sb.length() - suffix.length()));
}
}
//------------------------------------------------------------------------
// Optimizations
//------------------------------------------------------------------------
public void optimize() {
// Ideally, this pass should be the first pass run, however:
// 1) VariableReferenceCheck reports unexpected warnings if Normalize
// is done first.
// 2) ReplaceMessages, stripCode, and potentially custom passes rely on
// unmodified local names.
normalize();
PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker);
if (options.devMode == DevMode.EVERY_PASS) {
phaseOptimizer.setSanityCheck(sanityCheck);
}
phaseOptimizer.consume(getPassConfig().getOptimizations());
phaseOptimizer.process(externsRoot, jsRoot);
if (hasErrors()) {
return;
}
}
@Override
void setCssRenamingMap(CssRenamingMap map) {
options.cssRenamingMap = map;
}
@Override
CssRenamingMap getCssRenamingMap() {
return options.cssRenamingMap;
}
/**
* Reprocesses the current defines over the AST. This is used by GwtCompiler
* to generate N outputs for different targets from the same (checked) AST.
* For each target, we apply the target-specific defines by calling
* {@code processDefines} and then {@code optimize} to optimize the AST
* specifically for that target.
*/
public void processDefines() {
(new DefaultPassConfig(options)).processDefines.create(this)
.process(externsRoot, jsRoot
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>);
}
boolean isInliningForbidden() {
return options.propertyRenaming == PropertyRenamingPolicy.HEURISTIC ||
options.propertyRenaming ==
PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC;
}
/** Control Flow Analysis. */
ControlFlowGraph<Node> computeCFG() {
logger.info("Computing Control Flow Graph");
Tracer tracer = newTracer("computeCFG");
ControlFlowAnalysis cfa = new ControlFlowAnalysis(this, true);
process(cfa);
stopTracer(tracer, "computeCFG");
return cfa.getCfg();
}
public void normalize() {
logger.info("Normalizing");
startPass("normalize");
process(new Normalize(this, false));
endPass();
}
@Override
void prepareAst(Node root) {
Tracer tracer = newTracer("prepareAst");
CompilerPass pass = new PrepareAst(this);
pass.process(null, root);
stopTracer(tracer, "prepareAst");
}
void recordFunctionInformation() {
logger.info("Recording function information");
startPass("recordFunctionInformation");
RecordFunctionInformation recordFunctionInfoPass =
new RecordFunctionInformation(
this, getPassConfig().getIntermediateState().functionNames);
process(recordFunctionInfoPass);
functionInformationMap = recordFunctionInfoPass.getMap();
endPass();
}
protected final CodeChangeHandler.RecentChange recentChange =
new CodeChangeHandler.RecentChange();
private final List<CodeChangeHandler> codeChangeHandlers =
Lists.<CodeChangeHandler>newArrayList();
@Override
void addChangeHandler(CodeChangeHandler handler) {
codeChangeHandlers.add(handler);
}
@Override
void removeChangeHandler(CodeChangeHandler handler) {
codeChangeHandlers.remove(handler);
}
/**
* All passes should call reportCodeChange() when they alter
* the JS tree structure. This is verified by CompilerTestCase.
* This allows us to optimize to a fixed point.
*/
@Override
public void reportCodeChange() {
for (CodeChangeHandler handler : codeChangeHandlers) {
handler.reportChange();
}
}
@Override
public CodingConvention getCodingConvention() {
CodingConvention convention = options.getCodingConvention();
convention = convention != null ? convention : defaultCodingConvention
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>;
return convention;
}
@Override
public boolean isIdeMode() {
return options.ideMode;
}
@Override
Config getParserConfig() {
if (parserConfig == null) {
parserConfig = ParserRunner.createConfig(isIdeMode());
}
return parserConfig;
}
@Override
public boolean isTypeCheckingEnabled() {
return options.checkTypes;
}
//------------------------------------------------------------------------
// Error reporting
//------------------------------------------------------------------------
@Override
public void report(JSError error) {
CheckLevel level = error.level;
WarningsGuard guard = options.getWarningsGuard();
if (guard != null) {
CheckLevel newLevel = guard.level(error);
if (newLevel != null) {
level = newLevel;
}
}
if (level.isOn()) {
errorManager.report(level, error);
}
}
@Override
public CheckLevel getErrorLevel(JSError error) {
Preconditions.checkNotNull(options);
WarningsGuard guards = options.getWarningsGuard();
if (guards == null) {
return error.level;
} else {
return guards.level(error);
}
}
/**
* Report an internal error.
*/
@Override
void throwInternalError(String message, Exception cause) {
String finalMessage =
"INTERNAL COMPILER ERROR.\n" +
"Please report this problem.\n" + message;
RuntimeException e = new RuntimeException(finalMessage, cause);
if (cause != null) {
e.setStackTrace(cause.getStackTrace());
}
throw e;
}
/**
* Gets the number of errors.
*/
public int getErrorCount() {
return errorManager.getErrorCount();
}
/**
* Gets the number of warnings.
*/
public int getWarningCount() {
return errorManager.getWarningCount();
}
@Override
boolean hasHaltingErrors() {
return !isIdeMode() && getErrorCount() > 0;
}
/**
* Consults the {@link ErrorManager} to see if we've encountered errors
* that should halt compilation. <p>
*
* If {@link CompilerOptions#ideMode} is {@code true}, this function
* always returns {@code false} without consulting
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> the error manager. The
* error manager will continue to be told about new errors and warnings, but
* the compiler will complete compilation of all inputs.<p>
*/
public boolean hasErrors() {
return hasHaltingErrors();
}
/** Called from the compiler passes, adds debug info */
@Override
void addToDebugLog(String str) {
debugLog.append(str);
debugLog.append('\n');
logger.fine(str);
}
private SourceFile getSourceFileByName(String sourceName) {
if (inputsByName.containsKey(sourceName)) {
return inputsByName.get(sourceName).getSourceFile();
}
return null;
}
public String getSourceLine(String sourceName, int lineNumber) {
if (lineNumber < 1) {
return null;
}
SourceFile input = getSourceFileByName(sourceName);
if (input != null) {
return input.getLine(lineNumber);
}
return null;
}
public Region getSourceRegion(String sourceName, int lineNumber) {
if (lineNumber < 1) {
return null;
}
SourceFile input = getSourceFileByName(sourceName);
if (input != null) {
return input.getRegion(lineNumber);
}
return null;
}
//------------------------------------------------------------------------
// Package-private helpers
//------------------------------------------------------------------------
@Override
Node getNodeForCodeInsertion(JSModule module) {
if (module == null) {
if (inputs.isEmpty()) {
throw new IllegalStateException("No inputs");
}
return inputs.get(0).getAstRoot(this);
}
List<CompilerInput> moduleInputs = module.getInputs();
if (moduleInputs.size() > 0) {
return moduleInputs.get(0).getAstRoot(this);
}
throw new IllegalStateException("Root module has no inputs");
}
public SourceMap getSourceMap() {
return sourceMap;
}
VariableMap getVariableMap() {
return getPassConfig().getIntermediateState().variableMap;
}
VariableMap getPropertyMap() {
return getPassConfig().getIntermediateState().propertyMap;
}
CompilerOptions getOptions() {
return options;
}
FunctionInformationMap getFunctionalInformationMap() {
return functionInformationMap;
}
/**
*
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Sets the logging level for the com.google.javascript.jscomp package.
*/
public static void setLoggingLevel(Level level) {
logger.setLevel(level);
}
/** Gets the DOT graph of the AST generated at the end of compilation. */
public String getAstDotGraph() throws IOException {
if (jsRoot != null) {
ControlFlowAnalysis cfa = new ControlFlowAnalysis(this, true);
cfa.process(null, jsRoot);
return DotFormatter.toDot(jsRoot, cfa.getCfg());
} else {
return "";
}
}
@Override
public ErrorManager getErrorManager() {
if (options == null) {
initOptions(new CompilerOptions());
}
return errorManager;
}
@Override
List<CompilerInput> getInputsInOrder() {
return Collections.<CompilerInput>unmodifiableList(inputs);
}
/**
* Stores the internal compiler state just before optimization is performed.
* This can be saved and restored in order to efficiently optimize multiple
* different output targets without having to perform checking multiple times.
*
* NOTE: This does not include all parts of the compiler's internal state. In
* particular, JSSourceFiles and CompilerOptions are not recorded. In
* order to recreate a Compiler instance from scratch, you would need to
* call {@code init} with the same arguments as in the initial creation before
* restoring intermediate state.
*/
public static class IntermediateState implements Serializable {
private static final long serialVersionUID = 1L;
Node externsRoot;
private Node jsRoot;
private List<CompilerInput> externs;
private List<CompilerInput> inputs;
private List<JSModule> modules;
private PassConfig.State passConfigState;
private JSTypeRegistry typeRegistry;
private boolean normalized;
private IntermediateState() {}
}
/**
* Returns the current internal state, excluding the input files and modules.
*/
public IntermediateState getState() {
IntermediateState state = new IntermediateState();
state.externsRoot = externsRoot;
state.jsRoot = jsRoot;
state.externs = externs;
state.inputs = inputs;
state.modules = modules;
state.passConfigState = getPassConfig().getIntermediateState();
state.type
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Registry = typeRegistry;
state.normalized = normalized;
return state;
}
/**
* Sets the internal state to the capture given. Note that this assumes that
* the input files are already set up.
*/
public void setState(IntermediateState state) {
externsRoot = state.externsRoot;
jsRoot = state.jsRoot;
externs = state.externs;
inputs = state.inputs;
modules = state.modules;
passes = createPassConfigInternal();
getPassConfig().setIntermediateState(state.passConfigState);
typeRegistry = state.typeRegistry;
normalized = state.normalized;
}
@VisibleForTesting
List<CompilerInput> getInputsForTesting() {
return inputs;
}
@VisibleForTesting
List<CompilerInput> getExternsForTesting() {
return externs;
}
@Override
boolean hasRegExpGlobalReferences() {
return hasRegExpGlobalReferences;
}
@Override
void setHasRegExpGlobalReferences(boolean references) {
hasRegExpGlobalReferences = references;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.javascript.jscomp.parsing.ParserRunner;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import java.io.IOException;
import java.util.logging.Logger;
/**
* Generates an AST for a JavaScript source file.
*
*
*/
public class JsAst implements SourceAst {
private static final Logger logger_ = Logger.getLogger(JsAst.class.getName());
private static final long serialVersionUID = 1L;
private transient SourceFile sourceFile;
private String fileName;
private Node root;
public JsAst(SourceFile sourceFile) {
this.sourceFile = sourceFile;
this.fileName = sourceFile.getName();
}
@Override
public Node getAstRoot(AbstractCompiler compiler) {
if (root == null) {
createAst(compiler);
}
return root;
}
@Override
public void clearAst() {
root = null;
// While we're at it, clear out any saved text in the source file on
// the assumption that if we're dumping the parse tree, then we probably
// assume regenerating everything else is a smart idea also.
sourceFile.clearCachedSource();
}
@Override
public SourceFile getSourceFile() {
return sourceFile;
}
@Override
public void setSourceFile(SourceFile file) {
Preconditions.checkState(fileName.equals(file.getName()));
sourceFile = file;
}
private void createAst(AbstractCompiler compiler)
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
/**
* A source excerpt provider is responsible for building source code excerpt
* of specific locations, such as a specific line or a region around a
* given line number.
*
*
*/
public interface SourceExcerptProvider {
/**
* Source excerpt variety.
*/
enum SourceExcerpt {
/**
* Line excerpt.
*/
LINE {
@Override
public String get(SourceExcerptProvider source, String sourceName,
int lineNumber, ExcerptFormatter formatter) {
return formatter.formatLine(
source.getSourceLine(sourceName, lineNumber), lineNumber);
}
},
/**
* Region excerpt.
*/
REGION {
@Override
public String get(SourceExcerptProvider source, String sourceName,
int lineNumber, ExcerptFormatter formatter) {
return formatter.formatRegion(
source.getSourceRegion(sourceName, lineNumber));
}
};
/**
* Get a source excerpt string based on the type of the source excerpt.
*/
public abstract String get(SourceExcerptProvider source, String sourceName,
int lineNumber, ExcerptFormatter formatter);
}
/**
* Get the line indicated by the line number. This call will return only the
* specific line.
*
* @param lineNumber the line number, 1 being the first line of the file
* @return the line indicated, or {@code null} if it does not exist
*/
String getSourceLine(String sourceName, int lineNumber);
/**
* Get a region around the indicated line number. The exact definition of a
* region is implementation specific, but it must
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>details);
}
@Override public final String getMessage()
{
String details = details();
if (sourceName == null || lineNumber <= 0) {
return details;
}
StringBuilder buf = new StringBuilder(details);
buf.append(" (");
if (sourceName != null) {
buf.append(sourceName);
}
if (lineNumber > 0) {
buf.append('#');
buf.append(lineNumber);
}
buf.append(')');
return buf.toString();
}
public String details()
{
return super.getMessage();
}
/**
* Get the uri of the script source containing the error, or null
* if that information is not available.
*/
public final String sourceName()
{
return sourceName;
}
/**
* Initialize the uri of the script source containing the error.
*
* @param sourceName the uri of the script source reponsible for the error.
* It should not be <tt>null</tt>.
*
* @throws IllegalStateException if the method is called more then once.
*/
public final void initSourceName(String sourceName)
{
if (sourceName == null) throw new IllegalArgumentException();
if (this.sourceName != null) throw new IllegalStateException();
this.sourceName = sourceName;
}
/**
* Returns the line number of the statement causing the error,
* or zero if not available.
*/
public final int lineNumber()
{
return lineNumber;
}
/**
* Initialize the line number of the script statement causing the error.
*
* @param lineNumber the line number in the script source.
* It should be positive number.
*
* @throws IllegalStateException if the method is called more then once.
*/
public final void initLineNumber(int lineNumber)
{
if (lineNumber <= 0) throw new IllegalArgumentException(String.valueOf(lineNumber));
if (this.lineNumber > 0) throw new IllegalStateException();
this.lineNumber = lineNumber;
}
/**
* The column number of the location of the error, or zero if unknown.
*/
public final int columnNumber()
{
return columnNumber;
}
/**
* Initialize the column number of the script statement causing the error.
*
* @param columnNumber the
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
return name.endsWith(".js");
}
});
}
/**
* Get a string representing the script stack of this exception.
* If optimization is enabled, this corresponds to all java stack elements
* with a source name matching the <code>filter</code>.
* @param filter the file name filter to determine whether a file is a
* script file
* @return a script stack dump
* @since 1.6R6
*/
public String getScriptStackTrace(FilenameFilter filter)
{
// The real Rhino code here has been removed.
return "<No stack trace available>";
}
@Override public void printStackTrace(PrintWriter s)
{
if (interpreterStackInfo == null) {
super.printStackTrace(s);
} else {
s.print(generateStackTrace());
}
}
@Override public void printStackTrace(PrintStream s)
{
if (interpreterStackInfo == null) {
super.printStackTrace(s);
} else {
s.print(generateStackTrace());
}
}
private String sourceName;
private int lineNumber;
private String lineSource;
private int columnNumber;
Object interpreterStackInfo;
int[] interpreterLineData;
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
import java.util.Set;
/**
* Object type.
*
* In JavaScript, all object types have properties, and each of those
* properties has a type. Property types may be DECLARED, INFERRED, or
* UNKNOWN.
*
* DECLARED properties have an explicit type annotation, as in:
* <code>
* /xx @type {number} x/
* Foo.prototype.bar = 1;
* </code>
* This property may only hold number values, and an assignment to any
* other type of value is an error.
*
* INFERRED properties do not have an explicit type annotation. Rather,
* we try to find all the possible types that this property can hold.
* <code>
* Foo.prototype.bar = 1;
* </code>
* If the programmer assigns other types of values to this property,
* the property will take on the union of all these types.
*
* UNKNOWN properties are properties on the UNKNOWN type. The UNKNOWN
* type has all properties, but we do not know whether they are
* declared or inferred.
*
*
*/
public abstract class ObjectType extends JSType {
private boolean visited;
private JSDocInfo docInfo = null;
private boolean unknown = true;
ObjectType(JSTypeRegistry registry) {
super(registry);
}
/**
* Gets the declared default element type.
* @see ParameterizedType
*/
public JSType getParameterType() {
return null;
}
/**
* Gets the declared default index type.
* @see IndexedType
*/
public JSType getIndexType() {
return null;
}
/**
* Gets the docInfo for this type.
*/
@Override public JSDocInfo getJSDocInfo() {
if (docInfo != null) {
return docInfo;
} else if (getImplicitPrototype() != null) {
return getImplicitPrototype().getJSDocInfo();
} else {
return super.getJSDocInfo();
}
}
/**
* Sets the docInfo for this type from the given
* {@link JSDocInfo}. The {@code JSDocInfo} may be {@code null}.
*/
public void setJSDocInfo(JSDocInfo info
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>) {
docInfo = info;
}
/**
* Detects a cycle in the implicit prototype chain. This method accesses
* the {@link #getImplicitPrototype()} method and must therefore be
* invoked only after the object is sufficiently initialized to respond to
* calls to this method.<p>
*
* The method is not thread safe.<p>
*
* @return True iff an implicit prototype cycle was detected.
*/
final boolean detectImplicitPrototypeCycle() {
// detecting cycle
this.visited = true;
ObjectType p = getImplicitPrototype();
while (p != null) {
if (p.visited) {
return true;
} else {
p.visited = true;
}
p = p.getImplicitPrototype();
}
// clean up
p = this;
do {
p.visited = false;
p = p.getImplicitPrototype();
} while (p != null);
return false;
}
/**
* Gets the reference name for this object. This includes named types
* like constructors, prototypes, and enums. It notably does not include
* literal types like strings and booleans and structural types.
* @return the object's name or {@code null} if this is an anonymous
* object
*/
public abstract String getReferenceName();
/**
* Returns true if the object is named.
* @return true if the object is named, false if it is anonymous
*/
public boolean hasReferenceName() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
// super
TernaryValue result = super.testForEquality(that);
if (result != null) {
return result;
}
// objects are comparable to everything but null/undefined
if (that.isSubtype(
getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) {
return UNKNOWN;
} else {
return FALSE;
}
}
/**
* Gets this object's constructor.
* @return this object's constructor or {@code null} if it is a native
* object (constructed natively v.s. by instantiation of a function)
*/
public abstract FunctionType getConstructor();
/**
* Gets the implicit prototype (a.k.a. the {@code [[
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> called, so setting this incorrectly could result
* in live code being removed.
* @return True if the property was registered successfully, false if this
* conflicts with a previous property type declaration.
*/
abstract boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns);
/**
* Gets the docInfo on the specified property on this type. This should not
* be done implemented recursively, as you generally need to know exactly on
* which type in the prototype chain the JSDocInfo exists.
*/
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return null;
}
/**
* Sets the docInfo for the specified property from the
* {@link JSDocInfo} on its definition.
* @param info {@code JSDocInfo} for the property definition. May be
* {@code null}.
* @param inExterns {@code true} if this property was defined in an externs
* file. TightenTypes assumes that any function passed to an externs
* property could be called, so setting this incorrectly could result
* in live code being removed.
*/
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
// by default, do nothing
}
@Override
public JSType findPropertyType(String propertyName) {
return hasProperty(propertyName) ?
getPropertyType(propertyName) : null;
}
/**
* Gets the property type of the property whose name is given. If the
* underlying object does not have this property, the Unknown type is
* returned to indicate that no information is available on this property.
*
* @return the property's type or {@link UnknownType}. This method never
* returns {@code null}.
*/
public abstract JSType getPropertyType(String propertyName);
/**
* Checks whether the property whose name is given is present on the
* object.
*/
public abstract boolean hasProperty(String propertyName);
/**
* Checks whether the property whose name is given is present directly on
* the object. Returns false even if it is declared on a supertype.
*/
public boolean hasOwnProperty(String propertyName) {
return hasProperty(propertyName);
}
/** Returns the names of all
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> the properties directly on this type. */
public Set<String> getOwnPropertyNames() {
return new HashSet<String>();
}
/**
* Checks whether the property's type is inferred.
*/
public abstract boolean isPropertyTypeInferred(String propertyName);
/**
* Checks whether the property's type is declared.
*/
public abstract boolean isPropertyTypeDeclared(String propertyName);
/**
* Whether the given property is declared on this object.
*/
boolean hasOwnDeclaredProperty(String name) {
return hasOwnProperty(name) && isPropertyTypeDeclared(name);
}
/** Checks whether the property was defined in the externs. */
public boolean isPropertyInExterns(String propertyName) {
return false;
}
/**
* Gets the number of properties of this object.
*/
public abstract int getPropertiesCount();
/**
* Returns a list of properties defined or inferred on this type and any of
* its supertypes.
*/
public Set<String> getPropertyNames() {
Set<String> props = Sets.newHashSet();
collectPropertyNames(props);
return props;
}
/**
* Adds any properties defined on this type or its supertypes to the set.
*/
abstract void collectPropertyNames(Set<String> props);
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseObjectType(this);
}
/**
* Checks that the prototype is an implicit prototype of this object. Since
* each object has an implicit prototype, an implicit prototype's
* implicit prototype is also this implicit prototype's.
*
* @param prototype any prototype based object
*
* @return {@code true} if {@code prototype} is {@code equal} to any
* object in this object's implicit prototype chain.
*/
final boolean isImplicitPrototype(ObjectType prototype) {
for (ObjectType current = this;
current != null;
current = current.getImplicitPrototype()) {
if (current.isEquivalentTo(prototype)) {
return true;
}
}
return false;
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.TRUE;
}
/**
* We treat this as the unknown type if any of its implicit prototype
* properties is unknown.
*/
@Override
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
public boolean isUnknownType() {
// If the object is unknown now, check the supertype again,
// because it might have been resolved since the last check.
if (unknown) {
ObjectType implicitProto = getImplicitPrototype();
if (implicitProto == null ||
implicitProto.isNativeObjectType()) {
unknown = false;
} else {
unknown = implicitProto.isUnknownType();
}
}
return unknown;
}
@Override
public boolean isObject() {
return true;
}
/**
* Returns true if any cached valeus have been set for this type. If true,
* then the prototype chain should not be changed, as it might invalidate the
* cached values.
*/
public boolean hasCachedValues() {
return !unknown;
}
/** Whether this is a built-in object. */
public boolean isNativeObjectType() {
return false;
}
/**
* A null-safe version of JSType#toObjectType.
*/
public static ObjectType cast(JSType type) {
return type == null ? null : type.toObjectType();
}
/**
* Gets the interfaces implemented by the ctor associated with this type.
* Intended to be overridden by subclasses.
*/
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return ImmutableSet.of();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.CheckLevel;
import java.util.logging.Logger;
import java.util.logging.Level;
/**
* An error manager that logs errors and warnings using a logger in addition to
* collecting them in memory. Errors are logged at the SEVERE level and warnings
* are logged at the WARNING level.
*
*
*/
public class LoggerErrorManager extends BasicErrorManager {
private final MessageFormatter formatter;
private final Logger logger;
/**
* Creates an instance.
*/
public LoggerErrorManager(MessageFormatter formatter, Logger logger) {
this.formatter = formatter;
this.logger = logger;
}
/**
* Creates an instance with a source-less error formatter.
*/
public LoggerErrorManager(Logger logger) {
this(ErrorFormat.SOURCELESS.toFormatter(null, false), logger);
}
@Override
public void println(CheckLevel level, JSError error) {
switch (level) {
case ERROR:
logger.severe(error.format(level, formatter));
break;
case WARNING:
logger.warning(error.format(level, formatter));
break;
}
}
@Override
protected void printSummary() {
Level level = (getErrorCount() + getWarningCount() == 0) ?
Level.INFO : Level.WARNING;
if (getTypedPercent() > 0.0) {
logger.log(level, "{0} error(s), {1} warning(s), {2,number,#.#}% typed",
new Object[] {getErrorCount
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> /**
* Create a named type based on the reference.
*/
NamedType(JSTypeRegistry registry, String reference,
String sourceName, int lineno, int charno) {
super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
Preconditions.checkNotNull(reference);
this.reference = reference;
this.sourceName = sourceName;
this.lineno = lineno;
this.charno = charno;
}
@Override
void forgiveUnknownNames() {
forgiving = true;
}
/** Returns the type to which this refers (which is unknown if unresolved). */
public JSType getReferencedType() {
return referencedType;
}
@Override
public String getReferenceName() {
return reference;
}
@Override
public String toString() {
return reference;
}
@Override
public boolean hasReferenceName() {
return true;
}
@Override
boolean isNamedType() {
return true;
}
@Override
public boolean isNominalType() {
return true;
}
/**
* Two named types are equivalent if they are the same {@code
* ObjectType} object. This is complicated by the fact that isEquivalent
* is sometimes called before we have a chance to resolve the type
* names.
*
* @return {@code true} iff {@code that} == {@code this} or {@code that}
* is a {@link NamedType} whose reference is the same as ours,
* or {@code that} is the type we reference.
*/
@Override
public boolean isEquivalentTo(JSType that) {
if (this == that) {
return true;
}
ObjectType objType = ObjectType.cast(that);
if (objType != null) {
return objType.isNominalType() &&
reference.equals(objType.getReferenceName());
}
return false;
}
@Override
public int hashCode() {
return reference.hashCode();
}
/**
* Resolve the referenced type within the enclosing scope.
*/
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> enclosing) {
// TODO(user): Investigate whether it is really necessary to keep two
// different mechanisms for resolving named types, and if so, which
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.SourceExcerptProvider.SourceExcerpt;
/**
* Error formats available.
*/
public enum ErrorFormat {
LEGACY {
@Override
public MessageFormatter toFormatter(
SourceExcerptProvider source, boolean colorize) {
VerboseMessageFormatter formatter = new VerboseMessageFormatter(source);
formatter.setColorize(colorize);
return formatter;
}
},
SINGLELINE {
@Override
public MessageFormatter toFormatter(
SourceExcerptProvider source, boolean colorize) {
LightweightMessageFormatter formatter = new LightweightMessageFormatter(
source);
formatter.setColorize(colorize);
return formatter;
}
},
MULTILINE {
@Override
public MessageFormatter toFormatter(
SourceExcerptProvider source, boolean colorize) {
LightweightMessageFormatter formatter = new LightweightMessageFormatter(
source, SourceExcerpt.REGION);
formatter.setColorize(colorize);
return formatter;
}
},
SOURCELESS {
@Override
public MessageFormatter toFormatter(
SourceExcerptProvider source, boolean colorize) {
LightweightMessageFormatter formatter =
LightweightMessageFormatter.withoutSource();
formatter.setColorize(colorize);
return formatter;
}
};
/**
* Convert to a concrete formatter.
*/
public abstract MessageFormatter toFormatter(
SourceExcerptProvider source, boolean colorize);
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> assign {@code x} a type within the {@code f(x)}
* call. Since it has no possible type, we assign {@code x} the NoType,
* so that {@code f(x)} is legal no matter what the type of {@code f}'s
* first argument is.
*
*
* @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a>
*/
public final class NoType extends NoObjectType {
private static final long serialVersionUID = 1L;
NoType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNoObjectType() {
return false;
}
@Override
public boolean isNoType() {
return true;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
return true;
}
@Override
public JSType getLeastSupertype(JSType that) {
return that;
}
@Override
public JSType getGreatestSubtype(JSType that) {
if (that.isUnknownType()) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return this;
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.EMPTY;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNoType();
}
@Override
public String toString() {
return "None";
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.ObjectType;
import java.nio.charset.Charset;
import java.util.Set;
/**
* A code generator that outputs type annotations for functions and
* constructors.
*
*/
class TypedCodeGenerator extends CodeGenerator {
TypedCodeGenerator(CodeConsumer consumer, Charset outputCharset) {
super(consumer, outputCharset);
}
@Override
void add(Node n, Context context) {
Node parent = n.getParent();
if (parent != null
&& (parent.getType() == Token.BLOCK
|| parent.getType() == Token.SCRIPT)) {
if (n.getType() == Token.FUNCTION) {
add(getFunctionAnnotation(n));
} else if (n.getType() == Token.EXPR_RESULT
&& n.getFirstChild().getType() == Token.ASSIGN) {
Node rhs = n.getFirstChild().getLastChild();
add(getTypeAnnotation(rhs));
} else if (n.getType() == Token.VAR
&& n.getFirstChild().getFirstChild() != null
&& n.getFirstChild().getFirstChild().getType() == Token.FUNCTION) {
add(getFunctionAnnotation(n.getFirstChild().getFirstChild
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Type;
ParameterizedType(
JSTypeRegistry registry, ObjectType objectType, JSType parameterType) {
super(registry, objectType);
this.parameterType = parameterType;
}
@Override
public JSType getParameterType() {
return parameterType;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>;
ObjectType referencedType;
ProxyObjectType(JSTypeRegistry registry, ObjectType referencedType) {
super(registry);
this.referencedType = referencedType;
}
@Override
public String getReferenceName() {
return referencedType.getReferenceName();
}
@Override
public boolean hasReferenceName() {
return referencedType.hasReferenceName();
}
@Override public boolean matchesNumberContext() {
return referencedType.matchesNumberContext();
}
@Override
public boolean matchesStringContext() {
return referencedType.matchesStringContext();
}
@Override public boolean matchesObjectContext() {
return referencedType.matchesObjectContext();
}
@Override
public boolean canBeCalled() {
return referencedType.canBeCalled();
}
@Override
public boolean isUnknownType() {
return referencedType.isUnknownType();
}
@Override
public boolean isCheckedUnknownType() {
return referencedType.isCheckedUnknownType();
}
@Override
public boolean isNullable() {
return referencedType.isNullable();
}
@Override
public boolean isFunctionPrototypeType() {
return referencedType.isFunctionPrototypeType();
}
@Override
public boolean isEnumType() {
return referencedType.isEnumType();
}
@Override
public boolean isEnumElementType() {
return referencedType.isEnumElementType();
}
@Override
public boolean isConstructor() {
return referencedType.isConstructor();
}
@Override
public boolean isNominalType() {
return referencedType.isNominalType();
}
@Override
public boolean isInstanceType() {
return referencedType.isInstanceType();
}
@Override
public boolean isInterface() {
return referencedType.isInterface();
}
@Override
public boolean isOrdinaryFunction() {
return referencedType.isOrdinaryFunction();
}
@Override
public TernaryValue testForEquality(JSType that) {
return referencedType.testForEquality(that);
}
@Override
public boolean isSubtype(JSType that) {
return referencedType.isSubtype(that);
}
@Override
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return referencedType.getCtorImplementedInterfaces();
}
@Override
public boolean canAssignTo(JSType that) {
return referencedType.can
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>AssignTo(that);
}
@Override
public boolean isEquivalentTo(JSType that) {
if (this == that) {
return true;
}
return referencedType.isEquivalentTo(that);
}
@Override
public int hashCode() {
return referencedType.hashCode();
}
@Override
public String toString() {
return referencedType.toString();
}
@Override
public ObjectType getImplicitPrototype() {
return referencedType.getImplicitPrototype();
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns) {
return referencedType.defineProperty(propertyName, type, inferred,
inExterns);
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return referencedType.isPropertyTypeDeclared(propertyName);
}
@Override
public boolean isPropertyTypeInferred(String propertyName) {
return referencedType.isPropertyTypeInferred(propertyName);
}
@Override
public boolean isPropertyInExterns(String propertyName) {
return referencedType.isPropertyInExterns(propertyName);
}
@Override
public int getPropertiesCount() {
return referencedType.getPropertiesCount();
}
@Override
protected void collectPropertyNames(Set<String> props) {
referencedType.collectPropertyNames(props);
}
@Override
public JSType findPropertyType(String propertyName) {
return referencedType.findPropertyType(propertyName);
}
@Override
public JSType getPropertyType(String propertyName) {
return referencedType.getPropertyType(propertyName);
}
@Override
public JSDocInfo getJSDocInfo() {
return referencedType.getJSDocInfo();
}
@Override
public void setJSDocInfo(JSDocInfo info) {
referencedType.setJSDocInfo(info);
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return referencedType.getOwnPropertyJSDocInfo(propertyName);
}
@Override
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
referencedType.setPropertyJSDocInfo(propertyName, info, inExterns);
}
@Override
public boolean hasProperty(String propertyName) {
return referenced
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Type.hasProperty(propertyName);
}
@Override
public boolean hasOwnProperty(String propertyName) {
return referencedType.hasOwnProperty(propertyName);
}
@Override
public Set<String> getOwnPropertyNames() {
return referencedType.getOwnPropertyNames();
}
@Override
public FunctionType getConstructor() {
return referencedType.getConstructor();
}
@Override
public JSType getParameterType() {
return referencedType.getParameterType();
}
@Override
public JSType getIndexType() {
return referencedType.getIndexType();
}
@Override
public <T> T visit(Visitor<T> visitor) {
return referencedType.visit(visitor);
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
referencedType = (ObjectType) referencedType.resolve(t, scope);
return this;
}
@Override
public String toDebugHashCodeString() {
return "{proxy:" + referencedType.toDebugHashCodeString() + "}";
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
private JSType currentClass = null;
CheckAccessControls(AbstractCompiler compiler) {
this.compiler = compiler;
this.validator = compiler.getTypeValidator();
}
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
public void enterScope(NodeTraversal t) {
if (!t.inGlobalScope()) {
Node n = t.getScopeRoot();
Node parent = n.getParent();
if (isDeprecatedFunction(n, parent)) {
deprecatedDepth++;
}
if (methodDepth == 0) {
currentClass = getClassOfMethod(n, parent);
}
methodDepth++;
}
}
public void exitScope(NodeTraversal t) {
if (!t.inGlobalScope()) {
Node n = t.getScopeRoot();
Node parent = n.getParent();
if (isDeprecatedFunction(n, parent)) {
deprecatedDepth--;
}
methodDepth--;
if (methodDepth == 0) {
currentClass = null;
}
}
}
/**
* Gets the type of the class that "owns" a method, or null if
* we know that its un-owned.
*/
private JSType getClassOfMethod(Node n, Node parent) {
if (parent.getType() == Token.ASSIGN) {
Node lValue = parent.getFirstChild();
if (lValue.isQualifiedName()) {
if (lValue.getType() == Token.GETPROP) {
// We have an assignment of the form "a.b = ...".
JSType lValueType = lValue.getJSType();
if (lValueType != null && lValueType.isConstructor()) {
// If a.b is a constructor, then everything in this function
// belongs to the "a.b" type.
return ((FunctionType) lValueType).getInstanceType();
} else {
// If a.b is not a constructor, then treat this as a method
// of whatever type is on "a".
return normalizeClassType(lValue.getFirstChild().getJSType());
}
} else {
// We have an assignment of the form "a = ...", so pull the
// type off the "a".
return normalizeClassType(lValue.getJSType());
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> } else if (NodeUtil.isFunctionDeclaration(n) ||
parent.getType() == Token.NAME) {
return normalizeClassType(n.getJSType());
}
return null;
}
/**
* Normalize the type of a constructor, its instance, and its prototype
* all down to the same type (the instance type).
*/
private JSType normalizeClassType(JSType type) {
if (type == null || type.isUnknownType()) {
return type;
} else if (type.isConstructor()) {
return ((FunctionType) type).getInstanceType();
} else if (type.isFunctionPrototypeType()) {
FunctionType owner = ((FunctionPrototypeType) type).getOwnerFunction();
if (owner.isConstructor()) {
return owner.getInstanceType();
}
}
return type;
}
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.NAME:
checkNameDeprecation(t, n, parent);
checkNameVisibility(t, n, parent);
break;
case Token.GETPROP:
checkPropertyDeprecation(t, n, parent);
checkPropertyVisibility(t, n, parent);
break;
case Token.NEW:
checkConstructorDeprecation(t, n, parent);
break;
}
}
/**
* Checks the given NEW node to ensure that access restrictions are obeyed.
*/
private void checkConstructorDeprecation(NodeTraversal t, Node n,
Node parent) {
JSType type = n.getJSType();
if (type != null) {
String deprecationInfo = getTypeDeprecationInfo(type);
if (deprecationInfo != null &&
shouldEmitDeprecationWarning(t, n, parent)) {
if (!deprecationInfo.isEmpty()) {
compiler.report(
t.makeError(n, DEPRECATED_CLASS_REASON,
type.toString(), deprecationInfo));
} else {
compiler.report(
t.makeError(n, DEPRECATED_CLASS, type.toString()));
}
}
}
}
/**
* Checks the given NAME node to ensure that access restrictions are obeyed.
*/
private void checkNameDe
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> =
new CrossModuleMethodMotion.IdGenerator();
/**
* Keys are arguments passed to getCssName() found during compilation; values
* are the number of times the key appeared as an argument to getCssName().
*/
private Map<String, Integer> cssNames = null;
/** The variable renaming map */
private VariableMap variableMap = null;
/** The property renaming map */
private VariableMap propertyMap = null;
/** The naming map for anonymous functions */
private VariableMap anonymousFunctionNameMap = null;
/** Fully qualified function names and globally unique ids */
private FunctionNames functionNames = null;
/** String replacement map */
private VariableMap stringMap = null;
public DefaultPassConfig(CompilerOptions options) {
super(options);
}
@Override
State getIntermediateState() {
return new State(
cssNames == null ? null : Maps.newHashMap(cssNames),
exportedNames == null ? null :
Collections.unmodifiableSet(exportedNames),
crossModuleIdGenerator, variableMap, propertyMap,
anonymousFunctionNameMap, stringMap, functionNames);
}
@Override
void setIntermediateState(State state) {
this.cssNames = state.cssNames == null ? null :
Maps.newHashMap(state.cssNames);
this.exportedNames = state.exportedNames == null ? null :
Sets.newHashSet(state.exportedNames);
this.crossModuleIdGenerator = state.crossModuleIdGenerator;
this.variableMap = state.variableMap;
this.propertyMap = state.propertyMap;
this.anonymousFunctionNameMap = state.anonymousFunctionNameMap;
this.stringMap = state.stringMap;
this.functionNames = state.functionNames;
}
@Override
protected List<PassFactory> getChecks() {
List<PassFactory> checks = Lists.newArrayList();
if (options.closurePass) {
checks.add(closureGoogScopeAliases);
}
if (options.nameAnonymousFunctionsOnly) {
if (options.anonymousFunctionNaming ==
AnonymousFunctionNamingPolicy.MAPPED) {
checks.add(nameMappedAnonymousFunctions);
} else if (options.anonymousFunctionNaming ==
AnonymousFunctionNamingPolicy.UNMAPPED) {
checks.add(nameUnmappedAnonymousFunctions);
}
return checks;
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.nameReferenceReportPath.isEmpty()) {
checks.add(printNameReferenceReport);
}
assertAllOneTimePasses(checks);
return checks;
}
@Override
protected List<PassFactory> getOptimizations() {
List<PassFactory> passes = Lists.newArrayList();
// TODO(nicksantos): The order of these passes makes no sense, and needs
// to be re-arranged.
if (options.runtimeTypeCheck) {
passes.add(runtimeTypeCheck);
}
passes.add(createEmptyPass("beforeStandardOptimizations"));
if (!options.idGenerators.isEmpty()) {
passes.add(replaceIdGenerators);
}
// Optimizes references to the arguments variable.
if (options.optimizeArgumentsArray) {
passes.add(optimizeArgumentsArray);
}
// Remove all parameters that are constants or unused.
if (options.optimizeParameters) {
passes.add(removeUselessParameters);
}
// Abstract method removal works best on minimally modified code, and also
// only needs to run once.
if (options.closurePass && options.removeAbstractMethods) {
passes.add(removeAbstractMethods);
}
// Collapsing properties can undo constant inlining, so we do this before
// the main optimization loop.
if (options.collapseProperties) {
passes.add(collapseProperties);
}
// Tighten types based on actual usage.
if (options.tightenTypes) {
passes.add(tightenTypesBuilder);
}
// Property disambiguation should only run once and needs to be done
// soon after type checking, both so that it can make use of type
// information and so that other passes can take advantage of the renamed
// properties.
if (options.disambiguateProperties) {
passes.add(disambiguateProperties);
}
if (options.computeFunctionSideEffects) {
passes.add(markPureFunctions);
} else if (options.markNoSideEffectCalls) {
// TODO(user) The properties that this pass adds to CALL and NEW
// AST nodes increase the AST's in-memory size. Given that we are
// already running close to our memory limits, we could run into
// trouble if we end up using the @nosideeffects annotation
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Write a CompilerPass for this.
final PassFactory suspiciousCode =
new PassFactory("suspiciousCode", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
List<Callback> sharedCallbacks = Lists.newArrayList();
if (options.checkSuspiciousCode) {
sharedCallbacks.add(new CheckAccidentalSemicolon(CheckLevel.WARNING));
sharedCallbacks.add(new CheckSideEffects(CheckLevel.WARNING));
}
CheckLevel checkGlobalThisLevel = options.checkGlobalThisLevel;
if (checkGlobalThisLevel.isOn()) {
sharedCallbacks.add(
new CheckGlobalThis(compiler, checkGlobalThisLevel));
}
return combineChecks(compiler, sharedCallbacks);
}
};
/** Verify that all the passes are one-time passes. */
private void assertAllOneTimePasses(List<PassFactory> passes) {
for (PassFactory pass : passes) {
Preconditions.checkState(pass.isOneTimePass());
}
}
/** Verify that all the passes are multi-run passes. */
private void assertAllLoopablePasses(List<PassFactory> passes) {
for (PassFactory pass : passes) {
Preconditions.checkState(!pass.isOneTimePass());
}
}
/** Checks for validity of the control structures. */
private final PassFactory checkControlStructures =
new PassFactory("checkControlStructures", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ControlStructureCheck(compiler);
}
};
/** Checks that all constructed classes are goog.require()d. */
private final PassFactory checkRequires =
new PassFactory("checkRequires", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CheckRequiresForConstructors(compiler, options.checkRequires);
}
};
/** Makes sure @constructor is paired with goog.provides(). */
private final PassFactory checkProvides =
new PassFactory("checkProvides", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CheckProvides(compiler, options.checkProvides);
}
};
private static final DiagnosticType GENERATE_EXPORTS_ERROR =
DiagnosticType.error(
"JSC_GENERATE_EXPORT
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>S_ERROR",
"Exports can only be generated if export symbol/property " +
"functions are set.");
/** Generates exports for @export annotations. */
private final PassFactory generateExports =
new PassFactory("generateExports", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
CodingConvention convention = compiler.getCodingConvention();
if (convention.getExportSymbolFunction() != null &&
convention.getExportPropertyFunction() != null) {
return new GenerateExports(compiler,
convention.getExportSymbolFunction(),
convention.getExportPropertyFunction());
} else {
return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR);
}
}
};
/** Generates exports for functions associated with JSUnit. */
private final PassFactory exportTestFunctions =
new PassFactory("exportTestFunctions", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
CodingConvention convention = compiler.getCodingConvention();
if (convention.getExportSymbolFunction() != null) {
return new ExportTestFunctions(compiler,
convention.getExportSymbolFunction());
} else {
return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR);
}
}
};
/** Raw exports processing pass. */
final PassFactory gatherRawExports =
new PassFactory("gatherRawExports", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
final GatherRawExports pass = new GatherRawExports(
compiler);
return new CompilerPass() {
@Override
public void process(Node externs, Node root) {
pass.process(externs, root);
if (exportedNames == null) {
exportedNames = Sets.newHashSet();
}
exportedNames.addAll(pass.getExportedVariableNames());
}
};
}
};
/** Closure pre-processing pass. */
@SuppressWarnings("deprecation")
final PassFactory closurePrimitives =
new PassFactory("processProvidesAndRequires", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
final ProcessClosurePrimitives pass = new ProcessClosurePrimitives(
compiler,
options.brokenClosureRequiresLevel,
options.rewriteNewDateGoogNow);
return new CompilerPass() {
@Override
public void process(Node externs, Node
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> root) {
pass.process(externs, root);
exportedNames = pass.getExportedVariableNames();
}
};
}
};
/**
* The default i18n pass.
* A lot of the options are not configurable, because ReplaceMessages
* has a lot of legacy logic.
*/
private final PassFactory replaceMessages =
new PassFactory("replaceMessages", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new ReplaceMessages(compiler,
options.messageBundle,
/* warn about message dupes */
true,
/* allow messages with goog.getMsg */
JsMessage.Style.getFromParams(true, false),
/* if we can't find a translation, don't worry about it. */
false);
}
};
/** Applies aliases and inlines goog.scope. */
final PassFactory closureGoogScopeAliases =
new PassFactory("processGoogScopeAliases", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ScopedAliases(compiler);
}
};
/** Checks that CSS class names are wrapped in goog.getCssName */
private final PassFactory closureCheckGetCssName =
new PassFactory("checkMissingGetCssName", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
String blacklist = options.checkMissingGetCssNameBlacklist;
Preconditions.checkState(blacklist != null && !blacklist.isEmpty(),
"Not checking use of goog.getCssName because of empty blacklist.");
return new CheckMissingGetCssName(
compiler, options.checkMissingGetCssNameLevel, blacklist);
}
};
/**
* Processes goog.getCssName. The cssRenamingMap is used to lookup
* replacement values for the classnames. If null, the raw class names are
* inlined.
*/
private final PassFactory closureReplaceGetCssName =
new PassFactory("renameCssNames", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node jsRoot) {
Map<String, Integer> newCssNames = null;
if (options.gatherCssNames) {
newCssNames = Maps.new
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>HashMap();
}
(new ReplaceCssNames(compiler, newCssNames)).process(
externs, jsRoot);
cssNames = newCssNames;
}
};
}
};
/**
* Creates synthetic blocks to prevent FoldConstants from moving code
* past markers in the source.
*/
private final PassFactory createSyntheticBlocks =
new PassFactory("createSyntheticBlocks", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CreateSyntheticBlocks(compiler,
options.syntheticBlockStartMarker,
options.syntheticBlockEndMarker);
}
};
/** Various peephole optimizations. */
private final PassFactory peepholeOptimizations =
new PassFactory("peepholeOptimizations", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new PeepholeOptimizationsPass(compiler,
new PeepholeSubstituteAlternateSyntax(),
new PeepholeRemoveDeadCode(),
new PeepholeFoldConstants());
}
};
/** Checks that all variables are defined. */
private final PassFactory checkVars =
new PassFactory("checkVars", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new VarCheck(compiler);
}
};
/** Checks for RegExp references. */
private final PassFactory checkRegExp =
new PassFactory("checkRegExp", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
final CheckRegExp pass = new CheckRegExp(compiler);
return new CompilerPass() {
@Override
public void process(Node externs, Node root) {
pass.process(externs, root);
compiler.setHasRegExpGlobalReferences(
pass.isGlobalRegExpPropertiesUsed());
}
};
}
};
/** Checks that no vars are illegally shadowed. */
private final PassFactory checkShadowVars =
new PassFactory("variableShadowDeclarationCheck", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new VariableShadowDeclarationCheck(
compiler, options.checkShadowVars);
}
};
/** Checks that references to variables look reasonable. */
private final PassFactory checkVariableReferences =
new PassFactory("checkVariableReferences", true)
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new VariableReferenceCheck(
compiler, options.aggressiveVarCheck);
}
};
/** Pre-process goog.testing.ObjectPropertyString. */
private final PassFactory objectPropertyStringPreprocess =
new PassFactory("ObjectPropertyStringPreprocess", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ObjectPropertyStringPreprocess(compiler);
}
};
/** Creates a typed scope and adds types to the type registry. */
final PassFactory resolveTypes =
new PassFactory("resolveTypes", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new GlobalTypeResolver(compiler);
}
};
/** Rusn type inference. */
final PassFactory inferTypes =
new PassFactory("inferTypes", false) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node root) {
Preconditions.checkNotNull(topScope);
Preconditions.checkNotNull(typedScopeCreator);
makeTypeInference(compiler).process(externs, root);
}
};
}
};
/** Checks type usage */
private final PassFactory checkTypes =
new PassFactory("checkTypes", false) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node root) {
Preconditions.checkNotNull(topScope);
Preconditions.checkNotNull(typedScopeCreator);
TypeCheck check = makeTypeCheck(compiler);
check.process(externs, root);
compiler.getErrorManager().setTypedPercent(check.getTypedPercent());
}
};
}
};
/**
* Checks possible execution paths of the program for problems: missing return
* statements and dead code.
*/
private final PassFactory checkControlFlow =
new PassFactory("checkControlFlow", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
List<Callback> callbacks = Lists.newArrayList();
if (options.checkUnreachableCode.isOn()) {
callbacks.add(
new CheckUnreachableCode(compiler, options.checkUnreachableCode));
}
if (options
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.checkMissingReturn.isOn() && options.checkTypes) {
callbacks.add(
new CheckMissingReturn(compiler, options.checkMissingReturn));
}
return combineChecks(compiler, callbacks);
}
};
/** Checks access controls. Depends on type-inference. */
private final PassFactory checkAccessControls =
new PassFactory("checkAccessControls", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CheckAccessControls(compiler);
}
};
/** Executes the given callbacks with a {@link CombinedCompilerPass}. */
private static CompilerPass combineChecks(AbstractCompiler compiler,
List<Callback> callbacks) {
Preconditions.checkArgument(callbacks.size() > 0);
Callback[] array = callbacks.toArray(new Callback[callbacks.size()]);
return new CombinedCompilerPass(compiler, array);
}
/** A compiler pass that resolves types in the global scope. */
private class GlobalTypeResolver implements CompilerPass {
private final AbstractCompiler compiler;
GlobalTypeResolver(AbstractCompiler compiler) {
this.compiler = compiler;
}
@Override
public void process(Node externs, Node root) {
if (topScope == null) {
typedScopeCreator =
new MemoizedScopeCreator(new TypedScopeCreator(compiler));
topScope = typedScopeCreator.createScope(root.getParent(), null);
} else {
compiler.getTypeRegistry().resolveTypesInScope(topScope);
}
}
}
/** Checks global name usage. */
private final PassFactory checkGlobalNames =
new PassFactory("Check names", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node jsRoot) {
// Create a global namespace for analysis by check passes.
// Note that this class does all heavy computation lazily,
// so it's OK to create it here.
namespaceForChecks = new GlobalNamespace(compiler, jsRoot);
new CheckGlobalNames(compiler, options.checkGlobalNamesLevel)
.injectNamespace(namespaceForChecks).process(externs, jsRoot);
}
};
}
};
/** Checks for properties that are not read or written */
private final PassFactory checkSuspiciousProperties
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> =
new PassFactory("checkSuspiciousProperties", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new SuspiciousPropertiesCheck(
compiler,
options.checkUndefinedProperties,
options.checkUnusedPropertiesEarly ?
CheckLevel.WARNING : CheckLevel.OFF);
}
};
/** Checks that the code is ES5 or Caja compliant. */
private final PassFactory checkStrictMode =
new PassFactory("checkStrictMode", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new StrictModeCheck(compiler,
!options.checkSymbols, // don't check variables twice
!options.checkCaja); // disable eval check if not Caja
}
};
/** Override @define-annotated constants. */
final PassFactory processDefines =
new PassFactory("processDefines", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node jsRoot) {
Map<String, Node> replacements = getAdditionalReplacements(options);
replacements.putAll(options.getDefineReplacements());
new ProcessDefines(compiler, replacements)
.injectNamespace(namespaceForChecks).process(externs, jsRoot);
// Kill the namespace in the other class
// so that it can be garbage collected after all passes
// are through with it.
namespaceForChecks = null;
}
};
}
};
/** Checks that all constants are not modified */
private final PassFactory checkConsts =
new PassFactory("checkConsts", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ConstCheck(compiler);
}
};
/** Computes the names of functions for later analysis. */
private final PassFactory computeFunctionNames =
new PassFactory("computeFunctionNames", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return ((functionNames = new FunctionNames(compiler)));
}
};
/** Skips Caja-private properties in for-in loops */
private final PassFactory ignoreCajaProperties =
new PassFactory("ignoreCajaProperties", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler)
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
return new IgnoreCajaProperties(compiler);
}
};
/** Inserts runtime type assertions for debugging. */
private final PassFactory runtimeTypeCheck =
new PassFactory("runtimeTypeCheck", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new RuntimeTypeCheck(compiler,
options.runtimeTypeCheckLogFunction);
}
};
/** Generates unique ids. */
private final PassFactory replaceIdGenerators =
new PassFactory("replaceIdGenerators", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ReplaceIdGenerators(compiler, options.idGenerators);
}
};
/** Replace strings. */
private final PassFactory replaceStrings =
new PassFactory("replaceStrings", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
VariableMap map = null;
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
ReplaceStrings pass = new ReplaceStrings(
compiler,
options.replaceStringsPlaceholderToken,
options.replaceStringsFunctionDescriptions);
pass.process(externs, root);
stringMap = pass.getStringMap();
}
};
}
};
/** Optimizes the "arguments" array. */
private final PassFactory optimizeArgumentsArray =
new PassFactory("optimizeArgumentsArray", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new OptimizeArgumentsArray(compiler);
}
};
/** Removes unused or constant formal parameters. */
private final PassFactory removeUselessParameters =
new PassFactory("optimizeParameters", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
NameReferenceGraphConstruction c =
new NameReferenceGraphConstruction(compiler);
c.process(externs, root);
(new OptimizeParameters(compiler, c.getNameReferenceGraph())).process(
externs, root);
}
};
}
};
/** Remove variables set to goog.abstractMethod. */
private final PassFactory removeAbstractMethods =
new PassFactory("removeAbstractMethods", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new Google
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>CodeRemoval(compiler);
}
};
/** Collapses names in the global scope. */
private final PassFactory collapseProperties =
new PassFactory("collapseProperties", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CollapseProperties(
compiler, options.collapsePropertiesOnExternTypes,
!isInliningForbidden());
}
};
/**
* Try to infer the actual types, which may be narrower
* than the declared types.
*/
private final PassFactory tightenTypesBuilder =
new PassFactory("tightenTypes", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
if (!options.checkTypes) {
return new ErrorPass(compiler, TIGHTEN_TYPES_WITHOUT_TYPE_CHECK);
}
tightenTypes = new TightenTypes(compiler);
return tightenTypes;
}
};
/** Devirtualize property names based on type information. */
private final PassFactory disambiguateProperties =
new PassFactory("disambiguateProperties", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
if (tightenTypes == null) {
return DisambiguateProperties.forJSTypeSystem(compiler);
} else {
return DisambiguateProperties.forConcreteTypeSystem(
compiler, tightenTypes);
}
}
};
/**
* Chain calls to functions that return this.
*/
private final PassFactory chainCalls =
new PassFactory("chainCalls", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ChainCalls(compiler);
}
};
/**
* Rewrite instance methods as static methods, to make them easier
* to inline.
*/
private final PassFactory devirtualizePrototypeMethods =
new PassFactory("devirtualizePrototypeMethods", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new DevirtualizePrototypeMethods(compiler);
}
};
/**
* Look for function calls that are pure, and annotate them
* that way.
*/
private final PassFactory markPureFunctions =
new PassFactory("markPureFunctions", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new PureFunctionMarker
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>(
compiler, options.debugFunctionSideEffectsPath, false);
}
};
/**
* Look for function calls that have no side effects, and annotate them
* that way.
*/
private final PassFactory markNoSideEffectCalls =
new PassFactory("markNoSideEffectCalls", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new MarkNoSideEffectCalls(compiler);
}
};
/** Inlines variables heuristically. */
private final PassFactory inlineVariables =
new PassFactory("inlineVariables", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
if (isInliningForbidden()) {
// In old renaming schemes, inlining a variable can change whether
// or not a property is renamed. This is bad, and those old renaming
// schemes need to die.
return new ErrorPass(compiler, CANNOT_USE_PROTOTYPE_AND_VAR);
} else {
InlineVariables.Mode mode;
if (options.inlineVariables) {
mode = InlineVariables.Mode.ALL;
} else if (options.inlineLocalVariables) {
mode = InlineVariables.Mode.LOCALS_ONLY;
} else {
throw new IllegalStateException("No variable inlining option set.");
}
return new InlineVariables(compiler, mode, true);
}
}
};
/** Inlines variables that are marked as constants. */
private final PassFactory inlineConstants =
new PassFactory("inlineConstants", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new InlineVariables(
compiler, InlineVariables.Mode.CONSTANTS_ONLY, true);
}
};
/**
* Simplify expressions by removing the parts that have no side effects.
*/
private final PassFactory removeConstantExpressions =
new PassFactory("removeConstantExpressions", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new RemoveConstantExpressions(compiler);
}
};
/**
* Perform local control flow optimizations.
*/
private final PassFactory minimizeExitPoints =
new PassFactory("minimizeExitPoints", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new MinimizeExitPoints(compiler);
}
};
/**
* Use data flow analysis to
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> remove dead branches.
*/
private final PassFactory removeUnreachableCode =
new PassFactory("removeUnreachableCode", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new UnreachableCodeElimination(compiler, true);
}
};
/**
* Remove prototype properties that do not appear to be used.
*/
private final PassFactory removeUnusedPrototypeProperties =
new PassFactory("removeUnusedPrototypeProperties", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new RemoveUnusedPrototypeProperties(
compiler, options.removeUnusedPrototypePropertiesInExterns,
!options.removeUnusedVars);
}
};
/**
* Process smart name processing - removes unused classes and does referencing
* starting with minimum set of names.
*/
private final PassFactory smartNamePass =
new PassFactory("smartNamePass", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node root) {
NameAnalyzer na = new NameAnalyzer(compiler, false);
na.process(externs, root);
String reportPath = options.reportPath;
if (reportPath != null) {
try {
Files.write(na.getHtmlReport(), new File(reportPath),
Charsets.UTF_8);
} catch (IOException e) {
compiler.report(JSError.make(REPORT_PATH_IO_ERROR, reportPath));
}
}
if (options.smartNameRemoval) {
na.removeUnreferenced();
}
}
};
}
};
/** Inlines simple methods, like getters */
private PassFactory inlineGetters =
new PassFactory("inlineGetters", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new InlineGetters(compiler);
}
};
/** Kills dead assignments. */
private PassFactory deadAssignmentsElimination =
new PassFactory("deadAssignmentsElimination", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new DeadAssignmentsElimination(compiler);
}
};
/** Inlines function calls. */
private PassFactory inlineFunctions =
new PassFactory("inlineFunctions", false) {
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
boolean enableBlockInlining = !isInliningForbidden();
return new InlineFunctions(
compiler,
compiler.getUniqueNameIdSupplier(),
options.inlineFunctions,
options.inlineLocalFunctions,
enableBlockInlining);
}
};
/** Removes variables that are never used. */
private PassFactory removeUnusedVars =
new PassFactory("removeUnusedVars", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
boolean preserveAnonymousFunctionNames =
options.anonymousFunctionNaming != AnonymousFunctionNamingPolicy.OFF;
return new RemoveUnusedVars(
compiler,
options.removeUnusedVarsInGlobalScope,
preserveAnonymousFunctionNames);
}
};
/**
* Move global symbols to a deeper common module
*/
private PassFactory crossModuleCodeMotion =
new PassFactory("crossModuleCodeMotion", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CrossModuleCodeMotion(compiler, compiler.getModuleGraph());
}
};
/**
* Move methods to a deeper common module
*/
private PassFactory crossModuleMethodMotion =
new PassFactory("crossModuleMethodMotion", false) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CrossModuleMethodMotion(
compiler, crossModuleIdGenerator,
// Only move properties in externs if we're not treating
// them as exports.
options.removeUnusedPrototypePropertiesInExterns);
}
};
/** A data-flow based variable inliner. */
private final PassFactory flowSensitiveInlineVariables =
new PassFactory("flowSensitiveInlineVariables", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new FlowSensitiveInlineVariables(compiler);
}
};
/** Uses register-allocation algorithms to use fewer variables. */
private final PassFactory coalesceVariableNames =
new PassFactory("coalesceVariableNames", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CoalesceVariableNames(compiler, options.generatePseudoNames);
}
};
/**
* Some simple, local collapses (e.g., {@code var x; var y;} becomes
* {@code var x,y;}.
*/
private
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> final PassFactory collapseVariableDeclarations =
new PassFactory("collapseVariableDeclarations", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CollapseVariableDeclarations(compiler);
}
};
/**
* Simple global collapses of variable declarations.
*/
private final PassFactory groupVariableDeclarations =
new PassFactory("groupVariableDeclarations", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new GroupVariableDeclarations(compiler);
}
};
/**
* Extracts common sub-expressions.
*/
private final PassFactory extractPrototypeMemberDeclarations =
new PassFactory("extractPrototypeMemberDeclarations", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ExtractPrototypeMemberDeclarations(compiler);
}
};
/** Rewrites common function definitions to be more compact. */
private final PassFactory rewriteFunctionExpressions =
new PassFactory("rewriteFunctionExpressions", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new FunctionRewriter(compiler);
}
};
/** Collapses functions to not use the VAR keyword. */
private final PassFactory collapseAnonymousFunctions =
new PassFactory("collapseAnonymousFunctions", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new CollapseAnonymousFunctions(compiler);
}
};
/** Moves function declarations to the top, to simulate actual hoisting. */
private final PassFactory moveFunctionDeclarations =
new PassFactory("moveFunctionDeclarations", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new MoveFunctionDeclarations(compiler);
}
};
private final PassFactory nameUnmappedAnonymousFunctions =
new PassFactory("nameAnonymousFunctions", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new NameAnonymousFunctions(compiler);
}
};
private final PassFactory nameMappedAnonymousFunctions =
new PassFactory("nameAnonymousFunctions", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
NameAnonymousFunctionsMapped naf =
new NameAnonymousFunctionsMapped(compiler);
naf.process(externs, root);
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> anonymousFunctionNameMap = naf.getFunctionMap();
}
};
}
};
/** Alias external symbols. */
private final PassFactory aliasExternals =
new PassFactory("aliasExternals", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new AliasExternals(compiler, compiler.getModuleGraph(),
options.unaliasableGlobals, options.aliasableGlobals);
}
};
/**
* Alias string literals with global variables, to avoid creating lots of
* transient objects.
*/
private final PassFactory aliasStrings =
new PassFactory("aliasStrings", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new AliasStrings(
compiler,
compiler.getModuleGraph(),
options.aliasAllStrings ? null : options.aliasableStrings,
options.aliasStringsBlacklist,
options.outputJsStringUsage);
}
};
/** Aliases common keywords (true, false) */
private final PassFactory aliasKeywords =
new PassFactory("aliasKeywords", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new AliasKeywords(compiler);
}
};
/** Handling for the ObjectPropertyString primitive. */
private final PassFactory objectPropertyStringPostprocess =
new PassFactory("ObjectPropertyStringPostprocess", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ObjectPropertyStringPostprocess(compiler);
}
};
/**
* Renames properties so that the two properties that never appear on
* the same object get the same name.
*/
private final PassFactory ambiguateProperties =
new PassFactory("ambiguateProperties", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new AmbiguateProperties(
compiler, options.anonymousFunctionNaming.getReservedCharacters());
}
};
/**
* Mark the point at which the normalized AST assumptions no longer hold.
*/
private final PassFactory markUnnormalized =
new PassFactory("markUnnormalized", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
compiler.setUnnormalized();
}
};
}
};
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> /** Denormalize the AST for code generation. */
private final PassFactory denormalize =
new PassFactory("denormalize", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new Denormalize(compiler);
}
};
/** Inverting name normalization. */
private final PassFactory invertContextualRenaming =
new PassFactory("invertNames", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return MakeDeclaredNamesUnique.getContextualRenameInverter(compiler);
}
};
/**
* Renames properties.
*/
private final PassFactory renameProperties =
new PassFactory("renameProperties", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
VariableMap map = null;
if (options.inputPropertyMapSerialized != null) {
try {
map = VariableMap.fromBytes(options.inputPropertyMapSerialized);
} catch (ParseException e) {
return new ErrorPass(compiler,
JSError.make(INPUT_MAP_PROP_PARSE, e.getMessage()));
}
}
final VariableMap prevPropertyMap = map;
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
propertyMap = runPropertyRenaming(
compiler, prevPropertyMap, externs, root);
}
};
}
};
private VariableMap runPropertyRenaming(
AbstractCompiler compiler, VariableMap prevPropertyMap,
Node externs, Node root) {
char[] reservedChars =
options.anonymousFunctionNaming.getReservedCharacters();
switch (options.propertyRenaming) {
case HEURISTIC:
RenamePrototypes rproto = new RenamePrototypes(compiler, false,
reservedChars, prevPropertyMap);
rproto.process(externs, root);
return rproto.getPropertyMap();
case AGGRESSIVE_HEURISTIC:
RenamePrototypes rproto2 = new RenamePrototypes(compiler, true,
reservedChars, prevPropertyMap);
rproto2.process(externs, root);
return rproto2.getPropertyMap();
case ALL_UNQUOTED:
RenameProperties rprop = new RenameProperties(
compiler, options.generatePseudoNames, prevPropertyMap,
reservedChars);
rprop.process
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>(externs, root);
return rprop.getPropertyMap();
default:
throw new IllegalStateException(
"Unrecognized property renaming policy");
}
}
/** Renames variables. */
private final PassFactory renameVars =
new PassFactory("renameVars", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
VariableMap map = null;
if (options.inputVariableMapSerialized != null) {
try {
map = VariableMap.fromBytes(options.inputVariableMapSerialized);
} catch (ParseException e) {
return new ErrorPass(compiler,
JSError.make(INPUT_MAP_VAR_PARSE, e.getMessage()));
}
}
final VariableMap prevVariableMap = map;
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
variableMap = runVariableRenaming(
compiler, prevVariableMap, externs, root);
}
};
}
};
private VariableMap runVariableRenaming(
AbstractCompiler compiler, VariableMap prevVariableMap,
Node externs, Node root) {
char[] reservedChars =
options.anonymousFunctionNaming.getReservedCharacters();
boolean preserveAnonymousFunctionNames =
options.anonymousFunctionNaming != AnonymousFunctionNamingPolicy.OFF;
RenameVars rn = new RenameVars(
compiler,
options.renamePrefix,
options.variableRenaming == VariableRenamingPolicy.LOCAL,
preserveAnonymousFunctionNames,
options.generatePseudoNames,
prevVariableMap,
reservedChars,
exportedNames);
rn.process(externs, root);
return rn.getVariableMap();
}
/** Renames labels */
private final PassFactory renameLabels =
new PassFactory("renameLabels", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new RenameLabels(compiler);
}
};
/** Convert bracket access to dot access */
private final PassFactory convertToDottedProperties =
new PassFactory("convertToDottedProperties", true) {
@Override
protected CompilerPass createInternal(AbstractCompiler compiler) {
return new ConvertToDottedProperties(compiler);
}
};
/** Checks that all variables are defined. */
private final PassFactory sanityCheckVars =
new PassFactory("sanityCheckVars", true) {
@Override
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> protected CompilerPass createInternal(AbstractCompiler compiler) {
return new VarCheck(compiler, true);
}
};
/** Adds instrumentations according to an instrumentation template. */
private final PassFactory instrumentFunctions =
new PassFactory("instrumentFunctions", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
try {
FileReader templateFile =
new FileReader(options.instrumentationTemplate);
(new InstrumentFunctions(
compiler, functionNames,
options.instrumentationTemplate,
options.appNameStr,
templateFile)).process(externs, root);
} catch (IOException e) {
compiler.report(
JSError.make(AbstractCompiler.READ_ERROR,
options.instrumentationTemplate));
}
}
};
}
};
/**
* Create a no-op pass that can only run once. Used to break up loops.
*/
private static PassFactory createEmptyPass(String name) {
return new PassFactory(name, true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return runInSerial();
}
};
}
/**
* Runs custom passes that are designated to run at a particular time.
*/
private PassFactory getCustomPasses(
final CustomPassExecutionTime executionTime) {
return new PassFactory("runCustomPasses", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return runInSerial(options.customPasses.get(executionTime));
}
};
}
/**
* All inlining is forbidden in heuristic renaming mode, because inlining
* will ruin the invariants that it depends on.
*/
private boolean isInliningForbidden() {
return options.propertyRenaming == PropertyRenamingPolicy.HEURISTIC ||
options.propertyRenaming ==
PropertyRenamingPolicy.AGGRESSIVE_HEURISTIC;
}
/** Create a compiler pass that runs the given passes in serial. */
private static CompilerPass runInSerial(final CompilerPass ... passes) {
return runInSerial(Lists.newArrayList(passes));
}
/** Create a compiler pass that runs the given passes in serial. */
private static CompilerPass runInSerial(
final
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Collection<CompilerPass> passes) {
return new CompilerPass() {
@Override public void process(Node externs, Node root) {
for (CompilerPass pass : passes) {
pass.process(externs, root);
}
}
};
}
@VisibleForTesting
static Map<String, Node> getAdditionalReplacements(
CompilerOptions options) {
Map<String, Node> additionalReplacements = Maps.newHashMap();
if (options.markAsCompiled || options.closurePass) {
additionalReplacements.put(COMPILED_CONSTANT_NAME, new Node(Token.TRUE));
}
if (options.closurePass && options.locale != null) {
additionalReplacements.put(CLOSURE_LOCALE_CONSTANT_NAME,
Node.newString(options.locale));
}
return additionalReplacements;
}
/** A compiler pass that marks pure functions. */
private static class PureFunctionMarker implements CompilerPass {
private final AbstractCompiler compiler;
private final String reportPath;
private final boolean useNameReferenceGraph;
PureFunctionMarker(AbstractCompiler compiler, String reportPath,
boolean useNameReferenceGraph) {
this.compiler = compiler;
this.reportPath = reportPath;
this.useNameReferenceGraph = useNameReferenceGraph;
}
@Override
public void process(Node externs, Node root) {
DefinitionProvider definitionProvider = null;
if (useNameReferenceGraph) {
NameReferenceGraphConstruction graphBuilder =
new NameReferenceGraphConstruction(compiler);
graphBuilder.process(externs, root);
definitionProvider = graphBuilder.getNameReferenceGraph();
} else {
SimpleDefinitionFinder defFinder = new SimpleDefinitionFinder(compiler);
defFinder.process(externs, root);
definitionProvider = defFinder;
}
PureFunctionIdentifier pureFunctionIdentifier =
new PureFunctionIdentifier(compiler, definitionProvider);
pureFunctionIdentifier.process(externs, root);
if (reportPath != null) {
try {
Files.write(pureFunctionIdentifier.getDebugReport(),
new File(reportPath),
Charsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
private final PassFactory printNameReferenceGraph =
new PassFactory("printNameReferenceGraph",
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node jsRoot) {
NameReferenceGraphConstruction gc =
new NameReferenceGraphConstruction(compiler);
gc.process(externs, jsRoot);
String graphFileName = options.nameReferenceGraphPath;
try {
Files.write(DotFormatter.toDot(gc.getNameReferenceGraph()),
new File(graphFileName),
Charsets.UTF_8);
} catch (IOException e) {
compiler.report(
JSError.make(
NAME_REF_GRAPH_FILE_ERROR, e.getMessage(), graphFileName));
}
}
};
}
};
private final PassFactory printNameReferenceReport =
new PassFactory("printNameReferenceReport", true) {
@Override
protected CompilerPass createInternal(final AbstractCompiler compiler) {
return new CompilerPass() {
@Override
public void process(Node externs, Node jsRoot) {
NameReferenceGraphConstruction gc =
new NameReferenceGraphConstruction(compiler);
String reportFileName = options.nameReferenceReportPath;
try {
NameReferenceGraphReport report =
new NameReferenceGraphReport(gc.getNameReferenceGraph());
Files.write(report.getHtmlReport(),
new File(reportFileName),
Charsets.UTF_8);
} catch (IOException e) {
compiler.report(
JSError.make(
NAME_REF_REPORT_FILE_ERROR, e.getMessage(), reportFileName));
}
}
};
}
};
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> maybeLineBreak() {
maybeCutLine();
}
void maybeCutLine() {
}
void endLine() {
}
void notePreferredLineBreak() {
}
void beginBlock() {
if (statementNeedsEnded) {
append(";");
maybeLineBreak();
}
appendBlockStart();
endLine();
statementNeedsEnded = false;
}
void endBlock() {
endBlock(false);
}
void endBlock(boolean shouldEndLine) {
appendBlockEnd();
if (shouldEndLine) {
endLine();
}
statementNeedsEnded = false;
}
void listSeparator() {
add(",");
maybeLineBreak();
}
/**
* Indicates the end of a statement and a ';' may need to be added.
* But we don't add it now, in case we're at the end of a block (in which
* case we don't have to add the ';').
* See maybeEndStatement()
*/
void endStatement() {
endStatement(false);
}
void endStatement(boolean needSemiColon) {
if (needSemiColon) {
append(";");
maybeLineBreak();
statementNeedsEnded = false;
} else if (statementStarted) {
statementNeedsEnded = true;
}
}
/**
* This is to be called when we're in a statement. If the prev statement
* needs to be ended, add a ';'.
*/
void maybeEndStatement() {
// Add a ';' if we need to.
if (statementNeedsEnded) {
append(";");
maybeLineBreak();
endLine();
statementNeedsEnded = false;
}
statementStarted = true;
}
void endFunction() {
endFunction(false);
}
void endFunction(boolean statementContext) {
sawFunction = true;
if (statementContext) {
endLine();
}
}
void beginCaseBody() {
append(":");
}
void endCaseBody() {
}
void add(String newcode) {
maybeEndStatement();
if (newcode.length() == 0) {
return;
}
char c = newcode.charAt(0);
if ((isWordChar(c) || c == '\\') &&
isWordChar(getLastChar())) {
//
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* The {@code UnionType} implements a common JavaScript idiom in which the
* code is specifically designed to work with multiple input types. Because
* JavaScript always knows the runtime type of an object value, this is safer
* than a C union.<p>
*
* For instance, values of the union type {@code (String,boolean)} can be of
* type {@code String} or of type {@code boolean}. The commutativity of the
* statement is captured by making {@code (String,boolean)} and
* {@code (boolean,String)} equal.<p>
*
* The implementation of this class prevents the creation of nested
* unions.<p>
*/
public class UnionType extends JSType {
private static final long serialVersionUID = 1L;
Collection<JSType> alternates;
private final int hashcode;
/**
* Creates a union type.
*
* @param alternates the alternates of the union
*/
UnionType(JSTypeRegistry registry, Collection<JSType> alternates) {
super(registry);
this.alternates = alternates;
this.hashcode = this.alternates.hashCode();
}
/**
* Gets the alternate types of this union type.
* @return The alternate types of this union type. The returned set is
* immutable.
*/
public Iterable<JSType> getAlternates() {
return alternates;
}
@Override
void forgiveUnknownNames() {
for (JSType type : getAlternates()) {
type.forgiveUnknownNames();
}
}
/**
* This predicate is used to test whether a given type can appear in a
* numeric context, such as an operand of a multiply operator.
*
* @return true if the type can appear in a numeric context.
*/
@Override
public boolean matchesNumberContext() {
// TODO(user): Reverse this logic to make it correct instead of generous.
for (JSType t : alternates) {
if (t.matchesNumberContext()) {
return true;
}
}
return false;
}
/**
* This predicate is used to test whether a given type can appear
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> in a
* {@code String} context, such as an operand of a string concat ({@code +})
* operator.<p>
*
* All types have at least the potential for converting to {@code String}.
* When we add externally defined types, such as a browser OM, we may choose
* to add types that do not automatically convert to {@code String}.
*
* @return {@code true} if not {@link VoidType}
*/
@Override
public boolean matchesStringContext() {
// TODO(user): Reverse this logic to make it correct instead of generous.
for (JSType t : alternates) {
if (t.matchesStringContext()) {
return true;
}
}
return false;
}
/**
* This predicate is used to test whether a given type can appear in an
* {@code Object} context, such as the expression in a {@code with}
* statement.<p>
*
* Most types we will encounter, except notably {@code null}, have at least
* the potential for converting to {@code Object}. Host defined objects can
* get peculiar.<p>
*
* VOID type is included here because while it is not part of the JavaScript
* language, functions returning 'void' type can't be used as operands of
* any operator or statement.<p>
*
* @return {@code true} if the type is not {@link NullType} or
* {@link VoidType}
*/
@Override
public boolean matchesObjectContext() {
// TODO(user): Reverse this logic to make it correct instead of generous.
for (JSType t : alternates) {
if (t.matchesObjectContext()) {
return true;
}
}
return false;
}
@Override
public JSType findPropertyType(String propertyName) {
JSType propertyType = null;
for (JSType alternate : getAlternates()) {
// Filter out the null/undefined type.
if (alternate.isNullType() || alternate.isVoidType()) {
continue;
}
JSType altPropertyType = alternate.findPropertyType(propertyName);
if (altPropertyType == null) {
continue;
}
if (propertyType == null) {
propertyType = altPropertyType;
} else {
propertyType = property
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Type.getLeastSupertype(altPropertyType);
}
}
return propertyType;
}
@Override
public boolean canAssignTo(JSType that) {
boolean canAssign = true;
for (JSType t : alternates) {
if (t.isUnknownType()) {
return true;
}
canAssign &= t.canAssignTo(that);
}
return canAssign;
}
@Override
public boolean canBeCalled() {
for (JSType t : alternates) {
if (!t.canBeCalled()) {
return false;
}
}
return true;
}
@Override
public JSType restrictByNotNullOrUndefined() {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType t : alternates) {
restricted.addAlternate(t.restrictByNotNullOrUndefined());
}
return restricted.build();
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = null;
for (JSType t : alternates) {
TernaryValue test = t.testForEquality(that);
if (result == null) {
result = test;
} else if (!result.equals(test)) {
return UNKNOWN;
}
}
return result;
}
/**
* This predicate determines whether objects of this type can have the
* {@code null} value, and therefore can appear in contexts where
* {@code null} is expected.
*
* @return {@code true} for everything but {@code Number} and
* {@code Boolean} types.
*/
@Override
public boolean isNullable() {
for (JSType t : alternates) {
if (t.isNullable()) {
return true;
}
}
return false;
}
@Override
public boolean isUnknownType() {
for (JSType t : alternates) {
if (t.isUnknownType()) {
return true;
}
}
return false;
}
@Override
public JSType getLeastSupertype(JSType that) {
if (!that.isUnknownType()) {
for (JSType alternate : alternates) {
if (!alternate.isUnknownType() && that.isSubtype(alternate)) {
return this;
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> }
}
return getLeastSupertype(this, that);
}
JSType meet(JSType that) {
UnionTypeBuilder builder = new UnionTypeBuilder(registry);
for (JSType alternate : alternates) {
if (alternate.isSubtype(that)) {
builder.addAlternate(alternate);
}
}
if (that instanceof UnionType) {
for (JSType otherAlternate : ((UnionType) that).alternates) {
if (otherAlternate.isSubtype(this)) {
builder.addAlternate(otherAlternate);
}
}
} else if (that.isSubtype(this)) {
builder.addAlternate(that);
}
JSType result = builder.build();
if (!result.isNoType()) {
return result;
} else if (this.isObject() && that.isObject()) {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
} else {
return getNativeType(JSTypeNative.NO_TYPE);
}
}
/**
* Two union types are equal if they have the same number of alternates
* and all alternates are equal.
*/
@Override
public boolean isEquivalentTo(JSType object) {
if (object instanceof UnionType) {
UnionType that = (UnionType) object;
if (alternates.size() != that.alternates.size()) {
return false;
}
for (JSType alternate : that.alternates) {
if (!hasAlternate(alternate)) {
return false;
}
}
return true;
} else {
return false;
}
}
private boolean hasAlternate(JSType type) {
for (JSType alternate : alternates) {
if (alternate.isEquivalentTo(type)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return this.hashcode;
}
@Override
public boolean isUnionType() {
return true;
}
@Override
public boolean isObject() {
for (JSType alternate : alternates) {
if (!alternate.isObject()) {
return false;
}
}
return true;
}
/**
* A {@link UnionType} contains a given type (alternate) iff the member
* vector contains it.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Since the {@link #equals} method above conforms to
* the necessary semantics for the collection, everything works out just
* fine.
*
* @param alternate The alternate which might be in this union.
*
* @return {@code true} if the alternate is in the union
*/
public boolean contains(JSType alternate) {
return alternates.contains(alternate);
}
/**
* Returns a more restricted union type than {@code this} one, in which all
* subtypes of {@code type} have been removed.<p>
*
* Examples:
* <ul>
* <li>{@code (number,string)} restricted by {@code number} is
* {@code string}</li>
* <li>{@code (null, EvalError, URIError)} restricted by
* {@code Error} is {@code null}</li>
* </ul>
*
* @param type the supertype of the types to remove from this union type
*/
public JSType getRestrictedUnion(JSType type) {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType t : alternates) {
if (t.isUnknownType() || !t.isSubtype(type)) {
restricted.addAlternate(t);
}
}
return restricted.build();
}
@Override public String toString() {
StringBuilder result = new StringBuilder();
boolean firstAlternate = true;
result.append("(");
SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA);
sorted.addAll(alternates);
for (JSType t : sorted) {
if (!firstAlternate) {
result.append("|");
}
result.append(t.toString());
firstAlternate = false;
}
result.append(")");
return result.toString();
}
@Override
public boolean isSubtype(JSType that) {
for (JSType element : alternates) {
if (!element.isSubtype(that)) {
return false;
}
}
return true;
}
@Override
public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) {
// gather elements after restriction
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
restricted.addAlternate(
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> element.getRestrictedTypeGivenToBooleanOutcome(outcome));
}
return restricted.build();
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
BooleanLiteralSet literals = BooleanLiteralSet.EMPTY;
for (JSType element : alternates) {
literals = literals.union(element.getPossibleToBooleanOutcomes());
if (literals == BooleanLiteralSet.BOTH) {
break;
}
}
return literals;
}
@Override
public TypePair getTypesUnderEquality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderEquality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public TypePair getTypesUnderInequality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public TypePair getTypesUnderShallowInequality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
for (JSType element : alternates) {
TypePair p = element.getTypesUnderShallowInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
}
if (p.typeB != null) {
thatRestricted.addAlternate(p.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>typeB);
}
}
return new TypePair(
thisRestricted.build(),
thatRestricted.build());
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnionType(this);
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this); // for circularly defined types.
boolean changed = false;
ImmutableList.Builder<JSType> resolvedTypes = ImmutableList.builder();
for (JSType alternate : alternates) {
JSType newAlternate = alternate.resolve(t, scope);
changed |= (alternate != newAlternate);
resolvedTypes.add(alternate);
}
if (changed) {
Collection<JSType> newAlternates = resolvedTypes.build();
Preconditions.checkState(
newAlternates.hashCode() == this.hashcode);
alternates = newAlternates;
}
return this;
}
@Override
public String toDebugHashCodeString() {
List<String> hashCodes = Lists.newArrayList();
for (JSType a : alternates) {
hashCodes.add(a.toDebugHashCodeString());
}
return "{(" + Joiner.on(",").join(hashCodes) + ")}";
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> } else {
return getNativeType(JSTypeNative.NO_TYPE);
}
}
public JSType caseAllType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseVoidType() {
return getNativeType(JSTypeNative.NO_OBJECT_TYPE);
}
public JSType caseEnumElementType(EnumElementType type) {
return type.getPrimitiveType().visit(this);
}
}
NoObjectType(JSTypeRegistry registry) {
super(registry, null, null,
registry.createArrowType(null, null),
null, null, true, true);
getInternalArrowType().returnType = this;
this.setInstanceType(this);
}
@Override
public TernaryValue testForEquality(JSType that) {
return that.isEmptyType() ? TernaryValue.TRUE : TernaryValue.UNKNOWN;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
} else {
return that.isObject() && !that.isNoType();
}
}
@Override
public boolean isFunctionType() {
return false;
}
@Override
public boolean isNoObjectType() {
return true;
}
@Override
public JSType getLeastSupertype(JSType that) {
return that.visit(leastSupertypeVisitor);
}
@Override
public JSType getGreatestSubtype(JSType that) {
return that.visit(greatestSubtypeVisitor);
}
@Override
public ObjectType getImplicitPrototype() {
return null;
}
@Override
public String getReferenceName() {
return null;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean isEquivalentTo(JSType that) {
return this == that;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
@Override
public int getPropertiesCount() {
// Should never be called, returning the biggest number to highlight the
// 'unifying'
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> role of this type.
return Integer.MAX_VALUE;
}
@Override
public JSType getPropertyType(String propertyName) {
// Return the least type to be a proper subtype of all other objects.
return getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public boolean hasProperty(String propertyName) {
// has all properties, since it is any object
return true;
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns) {
// nothing, all properties are defined
return true;
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return null;
}
@Override
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
// Do nothing, specific properties do not have JSDocInfo.
}
@Override
public boolean isPropertyTypeInferred(String propertyName) {
return false;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNoObjectType();
}
@Override
public String toString() {
return "NoObject";
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
return this;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>";
if (d == Double.NEGATIVE_INFINITY)
return "-Infinity";
if (d == 0.0)
return "0";
if ((base < 2) || (base > 36)) {
throw Context.reportRuntimeError1(
"msg.bad.radix", Integer.toString(base));
}
if (base != 10) {
return DToA.JS_dtobasestr(base, d);
} else {
StringBuffer result = new StringBuffer();
DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d);
return result.toString();
}
}
/**
* If str is a decimal presentation of Uint32 value, return it as long.
* Othewise return -1L;
*/
public static long testUint32String(String str)
{
// The length of the decimal string representation of
// UINT32_MAX_VALUE, 4294967296
final int MAX_VALUE_LENGTH = 10;
int len = str.length();
if (1 <= len && len <= MAX_VALUE_LENGTH) {
int c = str.charAt(0);
c -= '0';
if (c == 0) {
// Note that 00,01 etc. are not valid Uint32 presentations
return (len == 1) ? 0L : -1L;
}
if (1 <= c && c <= 9) {
long v = c;
for (int i = 1; i != len; ++i) {
c = str.charAt(i) - '0';
if (!(0 <= c && c <= 9)) {
return -1;
}
v = 10 * v + c;
}
// Check for overflow
if ((v >>> 32) == 0) {
return v;
}
}
}
return -1;
}
static boolean isSpecialProperty(String s)
{
return s.equals("__proto__") || s.equals("__parent__");
}
// ------------------
// Statements
// ------------------
public static String getMessage0(String messageId)
{
return getMessage(messageId, null);
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import com.google.javascript.rhino.jstype.ObjectType;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* CodingConvention defines a set of hooks to customize the behavior of the
* Compiler for a specific team/company.
*
*
*
*/
public class DefaultCodingConvention implements CodingConvention {
@Override
public boolean isConstant(String variableName) {
return false;
}
@Override
public boolean isConstantKey(String variableName) {
return false;
}
@Override
public boolean isValidEnumKey(String key) {
return key != null && key.length() > 0;
}
@Override
public boolean isOptionalParameter(Node parameter) {
// be as lax as possible, but this must be mutually exclusive from
// var_args parameters.
return !isVarArgsParameter(parameter);
}
@Override
public boolean isVarArgsParameter(Node parameter) {
// be as lax as possible
return parameter.getParent().getLastChild() == parameter;
}
@Override
public boolean isExported(String name, boolean local) {
return local && name.startsWith("$super");
}
@Override
public boolean isExported(String name) {
return isExported(name, false) || isExported(name, true);
}
@
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Override
public boolean isPrivate(String name) {
return false;
}
@Override
public SubclassRelationship getClassesDefinedByCall(Node callNode) {
return null;
}
@Override
public boolean isSuperClassReference(String propertyName) {
return false;
}
@Override
public String extractClassNameIfProvide(Node node, Node parent) {
String message = "only implemented in GoogleCodingConvention";
throw new UnsupportedOperationException(message);
}
@Override
public String extractClassNameIfRequire(Node node, Node parent) {
String message = "only implemented in GoogleCodingConvention";
throw new UnsupportedOperationException(message);
}
@Override
public String getExportPropertyFunction() {
return null;
}
@Override
public String getExportSymbolFunction() {
return null;
}
@Override
public List<String> identifyTypeDeclarationCall(Node n) {
return null;
}
@Override
public String identifyTypeDefAssign(Node n) {
return null;
}
@Override
public void applySubclassRelationship(FunctionType parentCtor,
FunctionType childCtor, SubclassType type) {
// do nothing
}
@Override
public String getAbstractMethodName() {
return null;
}
@Override
public String getSingletonGetterClassName(Node callNode) {
return null;
}
@Override
public void applySingletonGetter(FunctionType functionType,
FunctionType getterType, ObjectType objectType) {
// do nothing.
}
@Override
public DelegateRelationship getDelegateRelationship(Node callNode) {
return null;
}
@Override
public void applyDelegateRelationship(
ObjectType delegateSuperclass, ObjectType delegateBase,
ObjectType delegator, FunctionType delegateProxy,
FunctionType findDelegate) {
// do nothing.
}
@Override
public String getDelegateSuperclassName() {
return null;
}
@Override
public void defineDelegateProxyPrototypeProperties(
JSTypeRegistry registry, Scope scope,
List<ObjectType> delegateProxyPrototypes) {
// do nothing.
}
@Override
public String getGlobalObject() {
return "window";
}
@Override
public boolean isPropertyTestFunction(Node call) {
return false;
}
@Override
public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t,
Node callNode) {
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> return null;
}
@Override
public Collection<AssertionFunctionSpec> getAssertionFunctions() {
return Collections.emptySet();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> fileName,
Generator generator) {
return new JSSourceFile(SourceFile.fromGenerator(fileName, generator));
}
private SourceFile referenced;
private JSSourceFile(SourceFile referenced) {
super(referenced.getName());
this.referenced = referenced;
}
@Override
public String getCode() throws IOException {
return referenced.getCode();
}
@Override
public void clearCachedSource() {
referenced.clearCachedSource();
}
@Override
@VisibleForTesting
String getCodeNoCache() {
return referenced.getCodeNoCache();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> this.newNodes = newNodes;
}
public boolean apply(Node n) {
if (!n.isQualifiedName()) {
return false;
}
Node current;
for (current = n;
current.getType() == Token.GETPROP;
current = current.getFirstChild()) {
if (newNodes.contains(current)) {
return true;
}
}
return current.getType() == Token.NAME && newNodes.contains(current);
}
}
/**
* Builds the namespace lazily.
*/
private void process() {
if (externsRoot != null) {
inExterns = true;
NodeTraversal.traverse(compiler, externsRoot, new BuildGlobalNamespace());
}
inExterns = false;
NodeTraversal.traverse(compiler, root, new BuildGlobalNamespace());
generated = true;
}
/**
* Determines whether a name reference in a particular scope is a global name
* reference.
*
* @param name A variable or property name (e.g. "a" or "a.b.c.d")
* @param s The scope in which the name is referenced
* @return Whether the name reference is a global name reference
*/
private boolean isGlobalNameReference(String name, Scope s) {
String topVarName = getTopVarName(name);
return isGlobalVarReference(topVarName, s);
}
/**
* Gets the top variable name from a possibly namespaced name.
*
* @param name A variable or qualified property name (e.g. "a" or "a.b.c.d")
* @return The top variable name (e.g. "a")
*/
private String getTopVarName(String name) {
int firstDotIndex = name.indexOf('.');
return firstDotIndex == -1 ? name : name.substring(0, firstDotIndex);
}
/**
* Determines whether a variable name reference in a particular scope is a
* global variable reference.
*
* @param name A variable name (e.g. "a")
* @param s The scope in which the name is referenced
* @return Whether the name reference is a global variable reference
*/
private boolean isGlobalVarReference(String name, Scope s) {
Scope.Var
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> v = s.getVar(name);
if (v == null && externsScope != null) {
v = externsScope.getVar(name);
}
return v != null && !v.isLocal();
}
/**
* Gets whether a scope is the global scope.
*
* @param s A scope
* @return Whether the scope is the global scope
*/
private boolean isGlobalScope(Scope s) {
return s.getParent() == null;
}
// -------------------------------------------------------------------------
/**
* Builds a tree representation of the global namespace. Omits prototypes.
*/
private class BuildGlobalNamespace extends AbstractPostOrderCallback {
private final Predicate<Node> nodeFilter;
BuildGlobalNamespace() {
this(null);
}
/**
* Builds a global namepsace, but only visits nodes that match the
* given filter.
*/
BuildGlobalNamespace(Predicate<Node> nodeFilter) {
this.nodeFilter = nodeFilter;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (nodeFilter != null && !nodeFilter.apply(n)) {
return;
}
// If we are traversing the externs, then we save a pointer to the scope
// generated by them, so that we can do lookups in it later.
if (externsRoot != null && n == externsRoot) {
externsScope = t.getScope();
}
String name;
boolean isSet = false;
Name.Type type = Name.Type.OTHER;
boolean isPropAssign = false;
switch (n.getType()) {
case Token.STRING:
// This may be a key in an object literal declaration.
name = null;
if (parent != null && parent.getType() == Token.OBJECTLIT) {
name = getNameForObjLitKey(n);
}
if (name == null) return;
isSet = true;
type = getValueType(n.getNext());
break;
case Token.NAME:
// This may be a variable get or set.
if (parent != null) {
switch (parent.getType()) {
case Token.VAR:
isSet = true;
Node rvalue = n.getFirstChild();
type = rvalue == null ? Name.Type.OTHER : getValueType(
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.Type.ALIASING_GET);
nameObj.addRef(get);
Ref.markTwins(set, get);
} else if (isConstructorOrEnumDeclaration(n, parent)) {
// Names with a @constructor or @enum annotation are always collapsed
nameObj.setIsClassOrEnum();
}
}
/**
* Determines whether a set operation is a constructor or enumeration
* declaration. The set operation may either be an assignment to a name,
* a variable declaration, or an object literal key mapping.
*
* @param n The node that represents the name being set
* @param parent Parent node of {@code n} (an ASSIGN, VAR, or OBJLIT node)
* @return Whether the set operation is either a constructor or enum
* declaration
*/
private boolean isConstructorOrEnumDeclaration(Node n, Node parent) {
JSDocInfo info;
int valueNodeType;
switch (parent.getType()) {
case Token.ASSIGN:
info = parent.getJSDocInfo();
valueNodeType = n.getNext().getType();
break;
case Token.VAR:
info = n.getJSDocInfo();
if (info == null) {
info = parent.getJSDocInfo();
}
Node valueNode = n.getFirstChild();
valueNodeType = valueNode != null ? valueNode.getType() : Token.VOID;
break;
default:
return false;
}
// Heed the annotations only if they're sensibly used.
return info != null &&
(info.isConstructor() && valueNodeType == Token.FUNCTION ||
info.hasEnumParameterType() && valueNodeType == Token.OBJECTLIT);
}
/**
* Updates our respresentation of the global namespace to reflect an
* assignment to a global name in a local scope.
*
* @param t The traversal
* @param n The node currently being visited
* @param parent {@code n}'s parent
* @param name The global name (e.g. "a" or "a.b.c.d")
*/
void handleSetFromLocal(NodeTraversal t, Node n, Node parent,
String name) {
if (maybeHandlePrototypePrefix(t, n, parent, name)) return;
Name node = getOrCreateName(name);
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Ref set = new Ref(t, n, Ref.Type.SET_FROM_LOCAL);
node.addRef(set);
if (isNestedAssign(parent)) {
// This assignment is both a set and a get that creates an alias.
Ref get = new Ref(t, n, Ref.Type.ALIASING_GET);
node.addRef(get);
Ref.markTwins(set, get);
}
}
/**
* Updates our respresentation of the global namespace to reflect a read
* of a global name.
*
* @param t The traversal
* @param n The node currently being visited
* @param parent {@code n}'s parent
* @param name The global name (e.g. "a" or "a.b.c.d")
*/
void handleGet(NodeTraversal t, Node n, Node parent, String name) {
if (maybeHandlePrototypePrefix(t, n, parent, name)) return;
Ref.Type type = Ref.Type.DIRECT_GET;
if (parent != null) {
switch (parent.getType()) {
case Token.IF:
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS:
case Token.NEG:
break;
case Token.CALL:
type = n == parent.getFirstChild()
? Ref.Type.CALL_GET
: Ref.Type.ALIASING_GET;
break;
case Token.NEW:
type = n == parent.getFirstChild()
? Ref.Type.DIRECT_GET
: Ref.Type.ALIASING_GET;
break;
case Token.OR:
case Token.AND:
// This node is x or y in (x||y) or (x&&y). We only know that an
// alias is not getting created for this name if the result is used
// in a boolean context or assigned to the same name
// (e.g. var a = a || {}).
type = determineGetTypeForHookOrBooleanExpr(t, parent, name);
break;
case Token.HOOK:
if (n != parent.getFirstChild()) {
// This node is y or z in (x?y:z). We only know that an alias is
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> // not getting created for this name if the result is assigned to
// the same name (e.g. var a = a ? a : {}).
type = determineGetTypeForHookOrBooleanExpr(t, parent, name);
}
break;
default:
type = Ref.Type.ALIASING_GET;
break;
}
}
handleGet(t, n, parent, name, type);
}
/**
* Determines whether the result of a hook (x?y:z) or boolean expression
* (x||y) or (x&&y) is assigned to a specific global name.
*
* @param t The traversal
* @param parent The parent of the current node in the traversal. This node
* should already be known to be a HOOK, AND, or OR node.
* @param name A name that is already known to be global in the current
* scope (e.g. "a" or "a.b.c.d")
* @return The expression's get type, either {@link Ref.Type#DIRECT_GET} or
* {@link Ref.Type#ALIASING_GET}
*/
Ref.Type determineGetTypeForHookOrBooleanExpr(
NodeTraversal t, Node parent, String name) {
Node prev = parent;
for (Node anc : parent.getAncestors()) {
switch (anc.getType()) {
case Token.EXPR_RESULT:
case Token.VAR:
case Token.IF:
case Token.WHILE:
case Token.FOR:
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS:
case Token.NEG:
return Ref.Type.DIRECT_GET;
case Token.HOOK:
if (anc.getFirstChild() == prev) {
return Ref.Type.DIRECT_GET;
}
break;
case Token.ASSIGN:
if (!name.equals(anc.getFirstChild().getQualifiedName())) {
return Ref.Type.ALIASING_GET;
}
break;
case Token.NAME: // a variable declaration
if (!name.equals(anc.getString())) {
return Ref.Type.ALIASING_GET;
}
break;
case Token.CALL:
if (anc.getFirst
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
ancestor = ancestor.parent) {
ancestor.hasClassOrEnumDescendant = true;
}
}
/**
* Determines whether this name is a prefix of at least one class or enum
* name. Because classes and enums are always collapsed, the namespace will
* have different properties in compiled code than in uncompiled code.
*
* For example, if foo.bar.DomHelper is a class, then foo and foo.bar are
* considered namespaces.
*/
boolean isNamespace() {
return hasClassOrEnumDescendant && type == Type.OBJECTLIT;
}
/**
* Determines whether this is a simple name (as opposed to a qualified
* name).
*/
boolean isSimpleName() {
return parent == null;
}
@Override public String toString() {
return fullName() + " (" + type + "): globalSets=" + globalSets +
", localSets=" + localSets + ", totalGets=" + totalGets +
", aliasingGets=" + aliasingGets + ", callGets=" + callGets;
}
String fullName() {
return parent == null ? name : parent.fullName() + '.' + name;
}
/**
* Tries to get the doc info for a given declaration ref.
*/
private static JSDocInfo getDocInfoForDeclaration(Ref ref) {
if (ref.node != null) {
Node refParent = ref.node.getParent();
switch (refParent.getType()) {
case Token.FUNCTION:
case Token.ASSIGN:
return refParent.getJSDocInfo();
case Token.VAR:
return ref.node == refParent.getFirstChild() ?
refParent.getJSDocInfo() : ref.node.getJSDocInfo();
}
}
return null;
}
}
// -------------------------------------------------------------------------
/**
* A global name reference. Contains references to the relevant parse tree
* node and its ancestors that may be affected.
*/
static class Ref {
enum Type {
SET_FROM_GLOBAL,
SET_FROM_LOCAL,
PROTOTYPE_GET,
ALIASING_GET, // Prevents a name's properties from being collapsed
DIRECT_GET, // Prevents a name from being completely eliminated
CALL_GET, // Prevents a name from being collapsed if never set
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Compiler compiler;
public CompilerInput(SourceAst ast) {
this(ast, ast.getSourceFile().getName(), false);
}
public CompilerInput(SourceAst ast, boolean isExtern) {
this(ast, ast.getSourceFile().getName(), isExtern);
}
public CompilerInput(SourceAst ast, String inputName, boolean isExtern) {
this.ast = ast;
this.name = inputName;
this.isExtern = isExtern;
}
public CompilerInput(JSSourceFile file) {
this(file, false);
}
public CompilerInput(JSSourceFile file, boolean isExtern) {
this.ast = new JsAst(file);
this.name = file.getName();
this.isExtern = isExtern;
}
/** Returns a name for this input. Must be unique across all inputs. */
@Override
public String getName() {
return name;
}
/** Gets the path relative to closure-base, if one is available. */
@Override
public String getPathRelativeToClosureBase() {
// TODO(nicksantos): Implement me.
throw new UnsupportedOperationException();
}
@Override
public Node getAstRoot(AbstractCompiler compiler) {
return ast.getAstRoot(compiler);
}
@Override
public void clearAst() {
ast.clearAst();
}
@Override
public SourceFile getSourceFile() {
return ast.getSourceFile();
}
@Override
public void setSourceFile(SourceFile file) {
ast.setSourceFile(file);
}
/** Returns the SourceAst object on which this input is based. */
public SourceAst getSourceAst() {
return ast;
}
/** Sets an error manager for routing error messages. */
public void setErrorManager(ErrorManager errorManager) {
this.errorManager = errorManager;
}
/** Sets an abstract compiler for doing parsing. */
public void setCompiler(AbstractCompiler compiler) {
this.compiler = compiler;
setErrorManager(compiler.getErrorManager());
}
/** Gets a list of types depended on by this input. */
@Override
public Collection<String> getRequires() {
Preconditions.checkNotNull(errorManager,
"Expected setErrorManager to be called first");
try {
regenerateDependencyInfoIf
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Necessary();
return Collections.<String>unmodifiableSet(requires);
} catch (IOException e) {
errorManager.report(CheckLevel.ERROR,
JSError.make(AbstractCompiler.READ_ERROR, getName()));
return ImmutableList.<String>of();
}
}
/** Gets a list of types provided by this input. */
@Override
public Collection<String> getProvides() {
Preconditions.checkNotNull(errorManager,
"Expected setErrorManager to be called first");
try {
regenerateDependencyInfoIfNecessary();
return Collections.<String>unmodifiableSet(provides);
} catch (IOException e) {
errorManager.report(CheckLevel.ERROR,
JSError.make(AbstractCompiler.READ_ERROR, getName()));
return ImmutableList.<String>of();
}
}
/**
* Regenerates the provides/requires if we need to do so.
*/
private void regenerateDependencyInfoIfNecessary() throws IOException {
// If the code is NOT a JsAst, then it was not originally JS code.
// Look at the Ast for dependency info.
if (!(ast instanceof JsAst)) {
Preconditions.checkNotNull(compiler,
"Expected setCompiler to be called first");
DepsFinder finder = new DepsFinder();
Node root = getAstRoot(compiler);
if (root == null) {
return;
}
finder.visitTree(getAstRoot(compiler));
// TODO(nicksantos|user): This caching behavior is a bit
// odd, and only works if you assume the exact call flow that
// clients are currently using. In that flow, they call
// getProvides(), then remove the goog.provide calls from the
// AST, and then call getProvides() again.
//
// This won't work for any other call flow, or any sort of incremental
// compilation scheme. The API needs to be fixed so callers aren't
// doing weird things like this, and then we should get rid of the
// multiple-scan strategy.
provides.addAll(finder.provides);
requires.addAll(finder.requires);
} else {
// Otherwise, look at the source code.
if (!generatedDependencyInfoFromSource) {
// Note: it's ok to use getName() instead of
// getPathRelativeToClosureBase() here because we're not using
//
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> compiler.
*
* This is a preferred internal constructor.
*/
private JSError(String sourceName, int lineno, int charno,
DiagnosticType type, CheckLevel level, String... arguments) {
this.type = type;
this.description = type.format.format(arguments);
this.lineNumber = lineno;
this.charno = charno;
this.sourceName = sourceName;
this.level = level == null ? type.level : level;
}
/**
* Creates a JSError for a source file location. Package private to avoid
* any entanglement with code outside of the compiler.
*
* This is a preferred internal constructor.
*/
private JSError(String sourceName, Node node,
DiagnosticType type, String... arguments) {
this(sourceName,
(node != null) ? node.getLineno() : -1,
(node != null) ? node.getCharno() : -1,
type, null, arguments);
}
public DiagnosticType getType() {
return type;
}
/**
* Format a message at the given level.
*
* @return the formatted message or {@code null}
*/
public String format(CheckLevel level, MessageFormatter formatter) {
switch (level) {
case ERROR:
return formatter.formatError(this);
case WARNING:
return formatter.formatWarning(this);
default:
return null;
}
}
@Override
public String toString() {
// TODO(user): remove custom toString.
return type.key + ". " + description + " at " +
(sourceName != null && sourceName.length() > 0 ?
sourceName : "(unknown source)") + " line " +
(lineNumber != -1 ? String.valueOf(lineNumber) : "(unknown line)") +
" : " + (charno != -1 ? String.valueOf(charno) : "(unknown column)");
}
/**
* Get the character number.
*/
public int getCharno() {
return charno;
}
@Override
public boolean equals(Object o) {
// Generated by Intellij IDEA
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>;
}
JSError jsError = (JSError) o;
if (charno != jsError.charno) {
return false;
}
if (lineNumber != jsError.lineNumber) {
return false;
}
if (!description.equals(jsError.description)) {
return false;
}
if (level != jsError.level) {
return false;
}
if (sourceName != null ? !sourceName.equals(jsError.sourceName)
: jsError.sourceName != null) {
return false;
}
if (!type.equals(jsError.type)) {
return false;
}
return true;
}
@Override
public int hashCode() {
// Generated by Intellij IDEA
int result = type.hashCode();
result = 31 * result + description.hashCode();
result = 31 * result + (sourceName != null ? sourceName.hashCode() : 0);
result = 31 * result + lineNumber;
result = 31 * result + level.hashCode();
result = 31 * result + charno;
return result;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> abstract T processSwitchCase(SwitchCase caseNode);
abstract T processSwitchStatement(SwitchStatement statementNode);
abstract T processThrowStatement(ThrowStatement statementNode);
abstract T processTryStatement(TryStatement statementNode);
abstract T processUnaryExpression(UnaryExpression exprNode);
abstract T processVariableDeclaration(VariableDeclaration declarationNode);
abstract T processVariableInitializer(VariableInitializer initializerNode);
abstract T processWhileLoop(WhileLoop loopNode);
abstract T processWithStatement(WithStatement statementNode);
abstract T processIllegalToken(AstNode node);
public T process(AstNode node) {
switch (node.getType()) {
case Token.ADD:
case Token.AND:
case Token.BITAND:
case Token.BITOR:
case Token.BITXOR:
case Token.COMMA:
case Token.DIV:
case Token.EQ:
case Token.GE:
case Token.GT:
case Token.IN:
case Token.INSTANCEOF:
case Token.LE:
case Token.LSH:
case Token.LT:
case Token.MOD:
case Token.MUL:
case Token.NE:
case Token.OR:
case Token.RSH:
case Token.SHEQ:
case Token.SHNE:
case Token.SUB:
case Token.URSH:
return processInfixExpression((InfixExpression) node);
case Token.ARRAYLIT:
return processArrayLiteral((ArrayLiteral) node);
case Token.ASSIGN:
case Token.ASSIGN_ADD:
case Token.ASSIGN_BITAND:
case Token.ASSIGN_BITOR:
case Token.ASSIGN_BITXOR:
case Token.ASSIGN_DIV:
case Token.ASSIGN_LSH:
case Token.ASSIGN_MOD:
case Token.ASSIGN_MUL:
case Token.ASSIGN_RSH:
case Token.ASSIGN_SUB:
case Token.ASSIGN_URSH:
return processAssignment((Assignment) node);
case Token.BITNOT:
case Token.DEC:
case Token.DELPROP:
case Token.INC:
case Token.NEG:
case Token.NOT:
case Token.POS:
case Token.TYPEOF:
case Token.VOID:
return processUnaryExpression((UnaryExpression) node);
case Token.BLOCK:
if (node instanceof Block
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> * Gets the boolean value of a node that represents a literal. This method
* effectively emulates the <code>Boolean()</code> JavaScript cast function.
*
* @throws IllegalArgumentException If {@code n} is not a literal value
*/
static TernaryValue getBooleanValue(Node n) {
switch (n.getType()) {
case Token.STRING:
return TernaryValue.forBoolean(n.getString().length() > 0);
case Token.NUMBER:
return TernaryValue.forBoolean(n.getDouble() != 0);
case Token.NULL:
case Token.FALSE:
case Token.VOID:
return TernaryValue.FALSE;
case Token.NAME:
String name = n.getString();
if ("undefined".equals(name)
|| "NaN".equals(name)) {
// We assume here that programs don't change the value of the keyword
// undefined to something other than the value undefined.
return TernaryValue.FALSE;
} else if ("Infinity".equals(name)) {
return TernaryValue.TRUE;
}
break;
case Token.TRUE:
case Token.ARRAYLIT:
case Token.OBJECTLIT:
case Token.REGEXP:
return TernaryValue.TRUE;
}
return TernaryValue.UNKNOWN;
}
/**
* Gets the value of a node as a String, or null if it cannot be converted.
* When it returns a non-null String, this method effectively emulates the
* <code>String()</code> JavaScript cast function.
*/
static String getStringValue(Node n) {
// TODO(user): Convert constant array, object, and regex literals as well.
switch (n.getType()) {
case Token.NAME:
case Token.STRING:
return n.getString();
case Token.NUMBER:
double value = n.getDouble();
long longValue = (long) value;
// Return "1" instead of "1.0"
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(n.getDouble());
}
case Token.FALSE:
case Token.TRUE:
case Token.NULL:
return Node.tokenToName(n.getType());
case Token.VOID:
return "undefined";
}
return null;
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
}
/**
* Gets the function's name. This method recognizes five forms:
* <ul>
* <li>{@code function name() ...}</li>
* <li>{@code var name = function() ...}</li>
* <li>{@code qualified.name = function() ...}</li>
* <li>{@code var name2 = function name1() ...}</li>
* <li>{@code qualified.name2 = function name1() ...}</li>
* </ul>
* In two last cases with named function expressions, the second name is
* returned (the variable of qualified name).
*
* @param n a node whose type is {@link Token#FUNCTION}
* @return the function's name, or {@code null} if it has no name
*/
static String getFunctionName(Node n) {
Node parent = n.getParent();
String name = n.getFirstChild().getString();
switch (parent.getType()) {
case Token.NAME:
// var name = function() ...
// var name2 = function name1() ...
return parent.getString();
case Token.ASSIGN:
// qualified.name = function() ...
// qualified.name2 = function name1() ...
return parent.getFirstChild().getQualifiedName();
default:
// function name() ...
return name != null && name.length() != 0 ? name : null;
}
}
/**
* Returns true if this is an immutable value.
*/
static boolean isImmutableValue(Node n) {
switch (n.getType()) {
case Token.STRING:
case Token.NUMBER:
case Token.NULL:
case Token.TRUE:
case Token.FALSE:
case Token.VOID:
return true;
case Token.NEG:
return isImmutableValue(n.getFirstChild());
case Token.NAME:
String name = n.getString();
// We assume here that programs don't change the value of the keyword
// undefined to something other than the value undefined.
return "undefined".equals(name)
|| "Infinity".equals(name)
|| "NaN".equals(name);
}
return false;
}
/**
* Returns true if this is a literal value. We define a literal value
* as any node that evaluates to the same thing regardless of when or
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>-effects (unlike '+='), and has no
* conditional aspects (unlike '||').
*/
static boolean isSimpleOperatorType(int type) {
switch (type) {
case Token.ADD:
case Token.BITAND:
case Token.BITNOT:
case Token.BITOR:
case Token.BITXOR:
case Token.COMMA:
case Token.DIV:
case Token.EQ:
case Token.GE:
case Token.GETELEM:
case Token.GETPROP:
case Token.GT:
case Token.INSTANCEOF:
case Token.LE:
case Token.LSH:
case Token.LT:
case Token.MOD:
case Token.MUL:
case Token.NE:
case Token.NOT:
case Token.RSH:
case Token.SHEQ:
case Token.SHNE:
case Token.SUB:
case Token.TYPEOF:
case Token.VOID:
case Token.POS:
case Token.NEG:
case Token.URSH:
return true;
default:
return false;
}
}
/**
* Creates an EXPR_RESULT.
*
* @param child The expression itself.
* @return Newly created EXPR node with the child as subexpression.
*/
public static Node newExpr(Node child) {
Node expr = new Node(Token.EXPR_RESULT, child)
.copyInformationFrom(child);
return expr;
}
/**
* Returns true if the node may create new mutable state, or change existing
* state.
*
* @see <a href="http://www.xkcd.org/326/">XKCD Cartoon</a>
*/
static boolean mayEffectMutableState(Node n) {
return mayEffectMutableState(n, null);
}
static boolean mayEffectMutableState(Node n, AbstractCompiler compiler) {
return checkForStateChangeHelper(n, true, compiler);
}
/**
* Returns true if the node which may have side effects when executed.
*/
static boolean mayHaveSideEffects(Node n) {
return mayHaveSideEffects(n, null);
}
static boolean mayHaveSideEffects(Node n, AbstractCompiler compiler) {
return checkForStateChangeHelper(n, false, compiler);
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>2 conditional ?:
* 3 logical-or ||
* 4 logical-and &&
* 5 bitwise-or |
* 6 bitwise-xor ^
* 7 bitwise-and &
* 8 equality == !=
* 9 relational < <= > >=
* 10 bitwise shift << >> >>>
* 11 addition/subtraction + -
* 12 multiply/divide * / %
* 13 negation/increment ! ~ - ++ --
* 14 call, member () [] .
*/
static int precedence(int type) {
switch (type) {
case Token.COMMA: return 0;
case Token.ASSIGN_BITOR:
case Token.ASSIGN_BITXOR:
case Token.ASSIGN_BITAND:
case Token.ASSIGN_LSH:
case Token.ASSIGN_RSH:
case Token.ASSIGN_URSH:
case Token.ASSIGN_ADD:
case Token.ASSIGN_SUB:
case Token.ASSIGN_MUL:
case Token.ASSIGN_DIV:
case Token.ASSIGN_MOD:
case Token.ASSIGN: return 1;
case Token.HOOK: return 2; // ?: operator
case Token.OR: return 3;
case Token.AND: return 4;
case Token.BITOR: return 5;
case Token.BITXOR: return 6;
case Token.BITAND: return 7;
case Token.EQ:
case Token.NE:
case Token.SHEQ:
case Token.SHNE: return 8;
case Token.LT:
case Token.GT:
case Token.LE:
case Token.GE:
case Token.INSTANCEOF:
case Token.IN: return 9;
case Token.LSH:
case Token.RSH:
case Token.URSH: return 10;
case Token.SUB:
case Token.ADD: return 11;
case Token.MUL:
case Token.MOD:
case Token.DIV: return 12;
case Token.INC:
case Token.DEC:
case Token.NEW:
case Token.DELPROP:
case Token.TYPEOF:
case Token.VOID:
case Token.NOT
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>BITOR: return "|";
case Token.OR: return "||";
case Token.BITXOR: return "^";
case Token.AND: return "&&";
case Token.BITAND: return "&";
case Token.SHEQ: return "===";
case Token.EQ: return "==";
case Token.NOT: return "!";
case Token.NE: return "!=";
case Token.SHNE: return "!==";
case Token.LSH: return "<<";
case Token.IN: return "in";
case Token.LE: return "<=";
case Token.LT: return "<";
case Token.URSH: return ">>>";
case Token.RSH: return ">>";
case Token.GE: return ">=";
case Token.GT: return ">";
case Token.MUL: return "*";
case Token.DIV: return "/";
case Token.MOD: return "%";
case Token.BITNOT: return "~";
case Token.ADD: return "+";
case Token.SUB: return "-";
case Token.POS: return "+";
case Token.NEG: return "-";
case Token.ASSIGN: return "=";
case Token.ASSIGN_BITOR: return "|=";
case Token.ASSIGN_BITXOR: return "^=";
case Token.ASSIGN_BITAND: return "&=";
case Token.ASSIGN_LSH: return "<<=";
case Token.ASSIGN_RSH: return ">>=";
case Token.ASSIGN_URSH: return ">>>=";
case Token.ASSIGN_ADD: return "+=";
case Token.ASSIGN_SUB: return "-=";
case Token.ASSIGN_MUL: return "*=";
case Token.ASSIGN_DIV: return "/=";
case Token.ASSIGN_MOD: return "%=";
case Token.VOID: return "void";
case Token.TYPEOF: return "typeof";
case Token.INSTANCEOF: return "instanceof";
default: return null;
}
}
/**
* Converts an operator's token value (see {@link Token}) to a string
* representation or fails.
*
* @param operator the operator's token value to convert
* @return the string representation
* @throws Error if the token value is not an operator
*/
static String op
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> }
private static class VarCollector implements Visitor {
final Map<String, Node> vars = Maps.newLinkedHashMap();
public void visit(Node n) {
if (n.getType() == Token.NAME) {
Node parent = n.getParent();
if (parent != null && parent.getType() == Token.VAR) {
String name = n.getString();
if (!vars.containsKey(name)) {
vars.put(name, n);
}
}
}
}
}
/**
* Retrieves vars declared in the current node tree, excluding descent scopes.
*/
public static Collection<Node> getVarsDeclaredInBranch(Node root) {
VarCollector collector = new VarCollector();
visitPreOrder(
root,
collector,
new MatchNotFunction());
return collector.vars.values();
}
/**
* @return {@code true} if the node an assignment to a prototype property of
* some constructor.
*/
static boolean isPrototypePropertyDeclaration(Node n) {
if (!isExprAssign(n)) {
return false;
}
return isPrototypeProperty(n.getFirstChild().getFirstChild());
}
static boolean isPrototypeProperty(Node n) {
String lhsString = n.getQualifiedName();
if (lhsString == null) {
return false;
}
int prototypeIdx = lhsString.indexOf(".prototype.");
return prototypeIdx != -1;
}
/**
* @return The class name part of a qualified prototype name.
*/
static Node getPrototypeClassName(Node qName) {
Node cur = qName;
while (isGetProp(cur)) {
if (cur.getLastChild().getString().equals("prototype")) {
return cur.getFirstChild();
} else {
cur = cur.getFirstChild();
}
}
return null;
}
/**
* @return The string property name part of a qualified prototype name.
*/
static String getPrototypePropertyName(Node qName) {
String qNameStr = qName.getQualifiedName();
int prototypeIdx = qNameStr.lastIndexOf(".prototype.");
int memberIndex = prototypeIdx + ".prototype".length() + 1;
return qNameStr.substring(memberIndex);
}
/**
* Create a node for an empty result expression:
* "void
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>0"
*/
static Node newUndefinedNode(Node srcReferenceNode) {
// TODO(johnlenz): Why this instead of the more common "undefined"?
Node node = new Node(Token.VOID, Node.newNumber(0));
if (srcReferenceNode != null) {
node.copyInformationFromForTree(srcReferenceNode);
}
return node;
}
/**
* Create a VAR node containing the given name and initial value expression.
*/
static Node newVarNode(String name, Node value) {
Node nodeName = Node.newString(Token.NAME, name);
if (value != null) {
Preconditions.checkState(value.getNext() == null);
nodeName.addChildToBack(value);
nodeName.copyInformationFrom(value);
}
Node var = new Node(Token.VAR, nodeName)
.copyInformationFrom(nodeName);
return var;
}
/**
* A predicate for matching name nodes with the specified node.
*/
private static class MatchNameNode implements Predicate<Node>{
final String name;
MatchNameNode(String name){
this.name = name;
}
public boolean apply(Node n) {
return n.getType() == Token.NAME
&& n.getString().equals(name);
}
}
/**
* A predicate for matching nodes with the specified type.
*/
static class MatchNodeType implements Predicate<Node>{
final int type;
MatchNodeType(int type){
this.type = type;
}
public boolean apply(Node n) {
return n.getType() == type;
}
}
/**
* A predicate for matching var or function declarations.
*/
static class MatchDeclaration implements Predicate<Node> {
public boolean apply(Node n) {
return isFunctionDeclaration(n) || n.getType() == Token.VAR;
}
}
/**
* A predicate for matching anything except function nodes.
*/
static class MatchNotFunction implements Predicate<Node>{
public boolean apply(Node n) {
return !isFunction(n);
}
}
/**
* A predicate for matching statements without exiting the current scope.
*/
static class MatchShallowStatement implements Predicate<Node>{
public boolean apply(Node n) {
Node parent = n.getParent();
return n.getType() ==
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
total += getCount(c, pred, traverseChildrenPred);
}
}
return total;
}
/**
* Interface for use with the visit method.
* @see #visit
*/
static interface Visitor {
void visit(Node node);
}
/**
* A pre-order traversal, calling Vistor.visit for each child matching
* the predicate.
*/
static void visitPreOrder(Node node,
Visitor vistor,
Predicate<Node> traverseChildrenPred) {
vistor.visit(node);
if (traverseChildrenPred.apply(node)) {
for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
visitPreOrder(c, vistor, traverseChildrenPred);
}
}
}
/**
* A post-order traversal, calling Vistor.visit for each child matching
* the predicate.
*/
static void visitPostOrder(Node node,
Visitor vistor,
Predicate<Node> traverseChildrenPred) {
if (traverseChildrenPred.apply(node)) {
for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
visitPostOrder(c, vistor, traverseChildrenPred);
}
}
vistor.visit(node);
}
/**
* @return Whether a TRY node has a finally block.
*/
static boolean hasFinally(Node n) {
Preconditions.checkArgument(n.getType() == Token.TRY);
return n.getChildCount() == 3;
}
/**
* @return The BLOCK node containing the CATCH node (if any)
* of a TRY.
*/
static Node getCatchBlock(Node n) {
Preconditions.checkArgument(n.getType() == Token.TRY);
return n.getFirstChild().getNext();
}
/**
* @return Whether BLOCK (from a TRY node) contains a CATCH.
* @see NodeUtil#getCatchBlock
*/
static boolean hasCatchHandler(Node n) {
Preconditions.checkArgument(n.getType() == Token.BLOCK);
return n.hasChildren() && n.getFirstChild().getType() == Token.CATCH;
}
/**
* @param fnNode The function.
* @return The Node containing the Function parameters.
*/
static Node
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
* Construct a tracer whose type is based on the short name of the object
* @param object Object to use as type name
* @param comment A comment
* @return new Tracer.
*/
static Tracer shortName(Object object, String comment) {
if (object == null) {
return new Tracer(comment);
}
return new Tracer(object.getClass().getSimpleName(), comment);
}
/**
* Converts 'v' to a string and pads it with up to 16 spaces for
* improved alignment.
* @param v The value to convert.
* @param digits_column_width The desired with of the string.
*/
private static String longToPaddedString(long v, int digits_column_width) {
int digit_width = numDigits(v);
StringBuilder sb = new StringBuilder();
appendSpaces(sb, digits_column_width - digit_width);
sb.append(v);
return sb.toString();
}
/**
* Gets the number of digits in an integer when printed in base 10. Assumes
* a positive integer.
* @param n The value.
* @return The number of digits in the string.
*/
private static int numDigits(long n) {
int i = 0;
do {
i++;
n = n / 10;
} while (n > 0);
return i;
}
/**
* Gets a string of spaces of the length specified.
* @param sb The string builder to append to.
* @param numSpaces The number of spaces in the string.
*/
@VisibleForTesting
static void appendSpaces(StringBuilder sb, int numSpaces) {
if (numSpaces > 16) {
logger.warning("Tracer.appendSpaces called with large numSpaces");
// Avoid long loop in case some bug in the caller
numSpaces = 16;
}
while (numSpaces >= 5) {
sb.append(" ");
numSpaces -= 5;
}
// We know it's less than 5 now
switch (numSpaces) {
case 1:
sb.append(" ");
break;
case 2:
sb.append(" ");
break;
case 3:
sb.append
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
long value = extraTracingStatistics.get(i).stop(startThread);
extraTracingValues[i] = value - extraTracingValues[i];
}
}
// Do nothing if the thread trace was not initialized.
if (!trace.isInitialized()) {
return 0;
}
trace.endEvent(this, silence_threshold);
return stopTimeMs - startTimeMs;
}
/** Stop the trace using the default silence_threshold
*
* @return The time that this trace actually ran.
*/
long stop() {
return stop(-1);
}
@Override public String toString() {
if (type == null) {
return comment;
} else {
return "[" + type + "] " + comment;
}
}
static void setDefaultSilenceThreshold(int threshold) {
getThreadTrace().defaultSilenceThreshold = threshold;
}
/**
* Initialize the trace associated with the current thread by clearing
* out any existing trace. There shouldn't be a trace so if one is
* found we log it as an error.
*/
static void initCurrentThreadTrace() {
ThreadTrace events = getThreadTrace();
if (!events.isEmpty()) {
logger.log(Level.WARNING,
"Non-empty timer log:\n" + events,
new Throwable());
clearThreadTrace();
// Grab a new thread trace if we find a previous non-empty ThreadTrace.
events = getThreadTrace();
}
// Mark the thread trace as initialized.
events.init();
}
static void initCurrentThreadTrace(int default_silence_threshold) {
initCurrentThreadTrace();
setDefaultSilenceThreshold(default_silence_threshold);
}
/**
* Returns a timer report similar to the one described in the class comment.
*
* @return The timer report as a string
*/
static String getCurrentThreadTraceReport() {
return getThreadTrace().toString();
}
/**
* Logs a timer report similar to the one described in the class comment.
*/
static void logCurrentThreadTrace() {
ThreadTrace trace = getThreadTrace();
// New threads must call Tracer.initCurrentThreadTrace() before Tracer
// statistics are gathered. This is a recent change (Jun 2007) that
// prevents spur
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>map != null) {
map.incrementBy(t.type, t.extraTracingValues[i]);
}
}
}
if (elapsed < silenceThreshold) {
stat.silent++;
if (typeToSilentMap != null) {
typeToSilentMap.incrementBy(t.type, 1);
}
}
}
}
boolean isEmpty() {
return events.size() == 0 && outstandingEvents.size() == 0;
}
void truncateOutstandingEvents() {
isOutstandingEventsTruncated = true;
outstandingEvents.clear();
}
void truncateEvents() {
isEventsTruncated = true;
events.clear();
}
/** Produces the lovely Trace seen in the class comments */
// Nullness checker does not understand that prettyPrint => indent != null
@SuppressWarnings("nullness")
@Override public String toString() {
int numDigits = getMaxDigits();
StringBuilder sb = new StringBuilder();
long etime = -1;
LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null;
for (Event e : events) {
if (prettyPrint && !e.isStart && !indent.isEmpty()) {
indent.pop();
}
sb.append(" ");
if (prettyPrint) {
sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits));
} else {
sb.append(e.toString(etime, "", 4));
}
etime = e.eventTime();
sb.append('\n');
if (prettyPrint && e.isStart) {
indent.push("| ");
}
}
if (outstandingEvents.size() != 0) {
long now = clock.currentTimeMillis();
sb.append(" Unstopped timers:\n");
for (Tracer t : outstandingEvents) {
sb.append(" ").
append(t).
append(" (").
append(now - t.startTimeMs).
append(" ms, started at ").
append(formatTime(t.startTimeMs)).
append(")\n");
}
}
for (String key : stats.keySet()) {
Stat stat = stats.get(key);
if (stat.count > 1) {
sb.append(" TOTAL ").
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2004 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
/**
* Tests for PeepholeFoldConstants in isolation. Tests for the interaction of
* multiple peephole passes are in PeepholeIntegrationTest.
*/
public class PeepholeFoldConstantsTest extends CompilerTestCase {
// TODO(user): Remove this when we no longer need to do string comparison.
private PeepholeFoldConstantsTest(boolean compareAsTree) {
super("", compareAsTree);
}
public PeepholeFoldConstantsTest() {
super("");
}
@Override
public void setUp() {
enableLineNumberCheck(true);
}
@Override
public CompilerPass getProcessor(final Compiler compiler) {
CompilerPass peepholePass = new PeepholeOptimizationsPass(compiler,
new PeepholeFoldConstants());
return peepholePass;
}
@Override
protected int getNumRepetitions() {
// Reduce this to 2 if we get better expression evaluators.
return 2;
}
private void foldSame(String js) {
testSame(js);
}
private void fold(String js, String expected) {
test(js, expected);
}
private void fold(String js, String expected, DiagnosticType warning) {
test(js, expected, warning);
}
// TODO(user): This is same as fold() except it uses string comparison. Any
// test that needs tell us where a folding is constructing an invalid AST.
private void assertResultString(String js, String expected) {
PeepholeFoldConstantsTest scTest = new PeepholeFoldConstantsTest
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> n.getProp(Node.SKIP_INDEXES_PROP));
add("]");
break;
case Token.LP:
add("(");
addList(first);
add(")");
break;
case Token.COMMA:
Preconditions.checkState(childCount == 2);
addList(first, false, context);
break;
case Token.NUMBER:
Preconditions.checkState(childCount == 0);
cc.addNumber(n.getDouble());
break;
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS:
case Token.NEG: {
// All of these unary operators are right-associative
Preconditions.checkState(childCount == 1);
cc.addOp(NodeUtil.opToStrNoFail(type), false);
addExpr(first, NodeUtil.precedence(type));
break;
}
case Token.HOOK: {
Preconditions.checkState(childCount == 3);
int p = NodeUtil.precedence(type);
addLeftExpr(first, p + 1, context);
cc.addOp("?", true);
addExpr(first.getNext(), 1);
cc.addOp(":", true);
addExpr(last, 1);
break;
}
case Token.REGEXP:
if (first.getType() != Token.STRING ||
last.getType() != Token.STRING) {
throw new Error("Expected children to be strings");
}
String regexp = regexpEscape(first.getString(), outputCharsetEncoder);
// I only use one .add because whitespace matters
if (childCount == 2) {
add(regexp + last.getString());
} else {
Preconditions.checkState(childCount == 1);
add(regexp);
}
break;
case Token.GET_REF:
add(first);
break;
case Token.REF_SPECIAL:
Preconditions.checkState(childCount == 1);
add(first);
add(".");
add((String) n.getProp(Node.NAME_PROP));
break;
case Token.FUNCTION:
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
Preconditions.checkState
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> : TYPE_1 } is a supertype of a record type
* of the form { b : TYPE_2, a : TYPE_1 } because B can be assigned to
* A and matches all constraints. Similarly, a defined type can be assigned
* to a record type so long as that defined type matches all property
* constraints of the record type. A record type of the form { a : A, b : B }
* can be assigned to a record of type { a : A }.
*
*
*/
public class RecordType extends PrototypeObjectType {
private static final long serialVersionUID = 1L;
private Map<String, JSType> properties = new HashMap<String, JSType>();
private boolean isFrozen = false;
/**
* Creates a record type.
*
* @param registry The type registry under which this type lives.
* @param properties A map of all the properties of this record type.
*/
RecordType(JSTypeRegistry registry, Map<String, JSType> properties) {
super(registry, null, null);
for (String property : properties.keySet()) {
defineDeclaredProperty(property, properties.get(property), false);
}
// Freeze the record type.
isFrozen = true;
}
@Override
public boolean isEquivalentTo(JSType other) {
if (!(other instanceof RecordType)) {
return false;
}
// Compare properties.
RecordType otherRecord = (RecordType) other;
Set<String> keySet = properties.keySet();
Map<String, JSType> otherProps = otherRecord.properties;
if (!otherProps.keySet().equals(keySet)) {
return false;
}
for (String key : keySet) {
if (!otherProps.get(key).isEquivalentTo(properties.get(key))) {
return false;
}
}
return true;
}
@Override
public ObjectType getImplicitPrototype() {
return registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE);
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns) {
if (isFrozen) {
return false;
}
if (!inferred) {
properties.put(propertyName, type);
}
return super.defineProperty(propertyName,
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> type, inferred, inExterns);
}
@Override
public JSType getLeastSupertype(JSType that) {
if (!that.isRecordType()) {
return super.getLeastSupertype(that);
}
RecordType thatRecord = (RecordType) that;
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
// The least supertype consist of those properties of the record
// type that both record types hold in common both by name and
// type of the properties themselves.
for (String property : properties.keySet()) {
if (thatRecord.hasProperty(property) &&
thatRecord.getPropertyType(property).isEquivalentTo(
getPropertyType(property))) {
builder.addProperty(property, getPropertyType(property));
}
}
return builder.build();
}
@Override
public JSType getGreatestSubtype(JSType that) {
if (that.isRecordType()) {
RecordType thatRecord = (RecordType) that;
RecordTypeBuilder builder = new RecordTypeBuilder(registry);
// The greatest subtype consists of those *unique* properties of both
// record types. If any property conflicts, then the NO_TYPE type
// is returned.
for (String property : properties.keySet()) {
if (thatRecord.hasProperty(property) &&
!thatRecord.getPropertyType(property).isEquivalentTo(
getPropertyType(property))) {
return registry.getNativeObjectType(JSTypeNative.NO_TYPE);
}
builder.addProperty(property, getPropertyType(property));
}
for (String property : thatRecord.properties.keySet()) {
if (!hasProperty(property)) {
builder.addProperty(property, thatRecord.getPropertyType(property));
}
}
return builder.build();
}
JSType greatestSubtype = super.getGreatestSubtype(that);
if (greatestSubtype.isNoObjectType() && !that.isNoObjectType()) {
// In this branch, the other type is some object type. We find
// the greatest subtype with the following algorithm:
// 1) For each property "x" of this record type, take the union
// of all classes with a property "x" with a compatible property type.
// and which are a subtype of {@code that}.
// 2) Take the
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> intersection of all of these unions.
for (Map.Entry<String, JSType> entry : properties.entrySet()) {
String propName = entry.getKey();
JSType propType = entry.getValue();
UnionTypeBuilder builder = new UnionTypeBuilder(registry);
for (ObjectType alt : registry.getTypesWithProperty(propName)) {
JSType altPropType = alt.getPropertyType(propName);
if (altPropType != null && !alt.isEquivalentTo(this) &&
alt.isSubtype(that) &&
(propType.isUnknownType() || altPropType.isUnknownType() ||
altPropType.isEquivalentTo(propType))) {
builder.addAlternate(alt);
}
}
greatestSubtype = greatestSubtype.getLeastSupertype(builder.build());
}
}
return greatestSubtype;
}
@Override
public boolean isRecordType() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
}
// Top of the record types is the empty record, or OBJECT_TYPE.
if (registry.getNativeObjectType(
JSTypeNative.OBJECT_TYPE).isSubtype(that)) {
return true;
}
// A type is a subtype of a record type if it itself is a record
// type and it has at least the same members as the parent record type
// with the same types.
if (!that.isRecordType()) {
return false;
}
return RecordType.isSubtype(this, (RecordType) that);
}
/** Determines if typeA is a subtype of typeB */
static boolean isSubtype(ObjectType typeA, RecordType typeB) {
// typeA is a subtype of record type typeB iff:
// 1) typeA has all the properties declared in typeB.
// 2) And for each property of typeB,
// 2a) if the property of typeA is declared, it must be equal
// to the type of the property of typeB,
// 2b) otherwise, it must be a subtype of the property of typeB.
//
// To figure out why this is true, consider the following pseudo-code:
// /** @
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>type {{a: (Object,null)}} */ var x;
// /** @type {{a: !Object}} */ var y;
// var z = {a: {}};
// x.a = null;
//
// y cannot be assigned to x, because line 4 would violate y's declared
// properties. But z can be assigned to x. Even though z and y are the
// same type, the properties of z are inferred--and so an assignment
// to the property of z would not violate any restrictions on it.
for (String property : typeB.properties.keySet()) {
if (!typeA.hasProperty(property)) {
return false;
}
JSType propA = typeA.getPropertyType(property);
JSType propB = typeB.getPropertyType(property);
if (!propA.isUnknownType() && !propB.isUnknownType()) {
if (typeA.isPropertyTypeDeclared(property)) {
if (!propA.isEquivalentTo(propB)) {
return false;
}
} else {
if (!propA.isSubtype(propB)) {
return false;
}
}
}
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{ ");
int i = 0;
for (String property : properties.keySet()) {
if (i > 0) {
sb.append(", ");
}
sb.append(property);
sb.append(" : ");
sb.append(properties.get(property).toString());
++i;
}
sb.append(" }");
return sb.toString();
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
for (Map.Entry<String, JSType> entry : properties.entrySet()) {
JSType type = entry.getValue();
JSType resolvedType = type.resolve(t, scope);
if (type != resolvedType) {
properties.put(entry.getKey(), resolvedType);
}
}
return super.resolveInternal(t, scope);
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Create an exception with the specified detail message.
*
* Errors internal to the JavaScript engine will simply throw a
* RuntimeException.
*
* @param sourceName the name of the source reponsible for the error
* @param lineNumber the line number of the source
* @param columnNumber the columnNumber of the source (may be zero if
* unknown)
* @param lineSource the source of the line containing the error (may be
* null if unknown)
*/
EcmaError(String errorName, String errorMessage,
String sourceName, int lineNumber,
String lineSource, int columnNumber)
{
recordErrorOrigin(sourceName, lineNumber, lineSource, columnNumber);
this.errorName = errorName;
this.errorMessage = errorMessage;
}
@Override public String details()
{
return errorName+": "+errorMessage;
}
/**
* Gets the name of the error.
*
* ECMA edition 3 defines the following
* errors: EvalError, RangeError, ReferenceError,
* SyntaxError, TypeError, and URIError. Additional error names
* may be added in the future.
*
* See ECMA edition 3, 15.11.7.9.
*
* @return the name of the error.
*/
public String getName()
{
return errorName;
}
/**
* Gets the message corresponding to the error.
*
* See ECMA edition 3, 15.11.7.10.
*
* @return an implemenation-defined string describing the error.
*/
public String getErrorMessage()
{
return errorMessage;
}
/**
* @deprecated Use {@link RhinoException#sourceName()} from the super class.
*/
@Deprecated
public String getSourceName()
{
return sourceName();
}
/**
* @deprecated Use {@link RhinoException#lineNumber()} from the super class.
*/
@Deprecated
public int getLineNumber()
{
return lineNumber();
}
/**
* @deprecated
* Use {@link RhinoException#columnNumber()} from the super class.
*/
@Deprecated
public int getColumnNumber() {
return columnNumber();
}
/**
* @deprecated Use {@link RhinoException#
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> = type.resolve(errorReporter, scope);
}
}
/**
* Returns whether this variable's type is inferred. To get the variable's
* type, see {@link #getType()}.
*/
public boolean isTypeInferred() {
return typeInferred;
}
public String getInputName() {
if (input == null)
return "<non-file>";
else
return input.getName();
}
public boolean isNoShadow() {
if (info != null && info.isNoShadow()) {
return true;
} else {
return false;
}
}
@Override public boolean equals(Object other) {
if (!(other instanceof Var)) {
return false;
}
Var otherVar = (Var) other;
return otherVar.nameNode == nameNode;
}
@Override public int hashCode() {
return nameNode.hashCode();
}
@Override
public String toString() {
return "Scope.Var " + name;
}
}
/**
* Creates a Scope given the parent Scope and the root node of the scope.
* @param parent The parent Scope. Cannot be null.
* @param rootNode Typically the FUNCTION node.
*/
Scope(Scope parent, Node rootNode) {
Preconditions.checkNotNull(parent);
Preconditions.checkArgument(rootNode != parent.rootNode);
this.parent = parent;
this.rootNode = rootNode;
JSType nodeType = rootNode.getJSType();
if (nodeType != null && nodeType instanceof FunctionType) {
thisType = ((FunctionType) nodeType).getTypeOfThis();
} else {
thisType = parent.thisType;
}
this.isBottom = false;
}
/**
* Creates a global Scope.
* @param rootNode Typically the global BLOCK node.
*/
Scope(Node rootNode, AbstractCompiler compiler) {
this.parent = null;
this.rootNode = rootNode;
thisType = compiler.getTypeRegistry().getNativeObjectType(GLOBAL_THIS);
this.isBottom = false;
}
/**
* Creates a empty Scope (bottom of the lattice).
* @param rootNode Typically a FUNCTION node or the global BLOCK node.
* @param thisType the type of {@code this} in this scope
*/
Scope
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>(Node rootNode, ObjectType thisType) {
this.parent = null;
this.rootNode = rootNode;
this.thisType = thisType;
this.isBottom = true;
}
/** Whether this is the bottom of the lattice. */
boolean isBottom() {
return isBottom;
}
/**
* Gets the container node of the scope. This is typically the FUNCTION
* node or the global BLOCK/SCRIPT node.
*/
public Node getRootNode() {
return rootNode;
}
public Scope getParent() {
return parent;
}
Scope getGlobalScope() {
Scope result = this;
while (result.getParent() != null) {
result = result.getParent();
}
return result;
}
@Override
public StaticScope<JSType> getParentScope() {
return parent;
}
/**
* Gets the type of {@code this} in the current scope.
*/
public ObjectType getTypeOfThis() {
return thisType;
}
/**
* Declares a variable whose type is inferred.
*
* @param name name of the variable
* @param nameNode the NAME node declaring the variable
* @param type the variable's type
* @param input the input in which this variable is defined.
*/
Var declare(String name, Node nameNode, JSType type, CompilerInput input) {
return declare(name, nameNode, type, input, true);
}
/**
* Declares a variable.
*
* @param name name of the variable
* @param nameNode the NAME node declaring the variable
* @param type the variable's type
* @param input the input in which this variable is defined.
* @param inferred Whether this variable's type is inferred (as opposed
* to declared).
*/
Var declare(String name, Node nameNode,
JSType type, CompilerInput input, boolean inferred) {
Preconditions.checkState(name != null && name.length() > 0);
// Make sure that it's declared only once
Preconditions.checkState(vars.get(name) == null);
Var var = new Var(inferred);
var.name = name;
var.nameNode = nameNode;
var.type = type;
var.scope = this;
var.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> /**
* The All type is the greatest type (top) and is never a subtype of
* another except itself or the Unknown type.
* @return {@code this.isEquivalentTo(that)}
*/
@Override
public boolean isSubtype(JSType that) {
return that.isAllType() || that.isUnknownType();
}
@Override
public boolean isAllType() {
return true;
}
@Override
public boolean matchesStringContext() {
// Be lenient.
return true;
}
@Override
public boolean matchesObjectContext() {
// Be lenient.
return true;
}
@Override
public boolean canBeCalled() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
return UNKNOWN;
}
@Override
public JSType getLeastSupertype(JSType that) {
if (that.isUnknownType()) {
return registry.getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
return this;
}
@Override
public JSType getGreatestSubtype(JSType that) {
return that;
}
@Override
public String toString() {
return "*";
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseAllType();
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
return this;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.NodeTraversal.Callback;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
/**
* A simple pass to ensure that all AST nodes have line numbers,
* an that the line numbers are monotonically increasing.
*
* @author nicksantos@google.com (Nick Santos)
*/
class LineNumberCheck implements Callback, CompilerPass {
static final DiagnosticType MISSING_LINE_INFO = DiagnosticType.error(
"JSC_MISSING_LINE_INFO",
"No source location information associated with {0}.\n" +
"Most likely a Node has been created with settings the source file " +
"and line/column location. Usually this is done using " +
"Node.copyInformationFrom and supplying a Node from the source AST.");
private final AbstractCompiler compiler;
private boolean requiresLineNumbers = false;
LineNumberCheck(AbstractCompiler compiler) {
this.compiler = compiler;
}
public void setCheckSubTree(Node root) {
requiresLineNumbers = true;
NodeTraversal.traverse(compiler, root, this);
}
public void process(Node externs, Node root) {
requiresLineNumbers = false;
NodeTraversal.traverse(compiler, root, this);
}
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
// Each JavaScript file is rooted in a script node, so we'll only
// have line number information inside the script node.
if (n.getType() ==
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Token.SCRIPT) {
requiresLineNumbers = true;
}
return true;
}
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.SCRIPT) {
requiresLineNumbers = false;
} else if (requiresLineNumbers) {
if (n.getLineno() == -1) {
// The tree version of the node is really the best diagnostic
// info we have to offer here.
compiler.report(
t.makeError(n, MISSING_LINE_INFO,
n.toStringTree()));
}
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> MAX_UNION_SIZE) {
return this;
}
// Look through the alternates we've got so far,
// and check if any of them are duplicates of
// one another.
Iterator<JSType> it = alternates.iterator();
while (it.hasNext()) {
JSType current = it.next();
if (alternate.isUnknownType() ||
current.isUnknownType()) {
if (alternate.isEquivalentTo(current)) {
// Alternate is unnecessary.
return this;
}
} else {
if (alternate.isSubtype(current)) {
// Alternate is unnecessary.
return this;
} else if (current.isSubtype(alternate)) {
// Alternate makes current obsolete
it.remove();
}
}
}
alternates.add(alternate);
result = null; // invalidate the memoized result
}
} else {
result = null;
}
return this;
}
/**
* Creates a union.
* @return A UnionType if it has two or more alternates, the
* only alternate if it has one and otherwise {@code NO_TYPE}.
*/
JSType build() {
if (result == null) {
if (isAllType) {
result = registry.getNativeType(ALL_TYPE);
} else if (isNativeUnknownType) {
if (areAllUnknownsChecked) {
result = registry.getNativeType(CHECKED_UNKNOWN_TYPE);
} else {
result = registry.getNativeType(UNKNOWN_TYPE);
}
} else {
int size = alternates.size();
if (size > MAX_UNION_SIZE) {
result = registry.getNativeType(UNKNOWN_TYPE);
} else {
if (size > 1) {
result = new UnionType(registry, getAlternateListCopy());
} else if (size == 1) {
result = alternates.iterator().next();
} else {
result = registry.getNativeType(NO_TYPE);
}
}
}
}
return result;
}
private static final Comparator<JSType> typeSorter =
new Comparator<JSType>() {
@Override public int compare(JSType a, JSType b) {
return b.hashCode() - a.hashCode();
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSTypeNative;
import com.google.javascript.rhino.jstype.ObjectType;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* This describes the Closure-specific JavaScript coding conventions.
*
*
*
*/
public class ClosureCodingConvention extends DefaultCodingConvention {
private static final String TYPEDEF_NAME = "goog.typedef";
static final DiagnosticType OBJECTLIT_EXPECTED = DiagnosticType.warning(
"JSC_REFLECT_OBJECTLIT_EXPECTED",
"Object literal expected as second argument");
/**
* Closure's goog.inherits adds a {@code superClass_} property to the
* subclass, and a {@code constructor} property.
*/
@Override
public void applySubclassRelationship(FunctionType parentCtor,
FunctionType childCtor, SubclassType type) {
if (type == SubclassType.INHERITS) {
childCtor.defineDeclaredProperty("superClass_",
parentCtor.getPrototype(), false);
childCtor.getPrototype().defineDeclaredProperty("constructor",
childCtor, false);
}
}
/**
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> * {@inheritDoc}
*
* <p>Understands several different inheritance patterns that occur in
* Google code (various uses of {@code inherits} and {@code mixin}).
*/
@Override
public SubclassRelationship getClassesDefinedByCall(Node callNode) {
Node callName = callNode.getFirstChild();
SubclassType type = typeofClassDefiningName(callName);
if (type != null) {
Node subclass = null;
Node superclass = callNode.getLastChild();
// There are six possible syntaxes for a class-defining method:
// SubClass.inherits(SuperClass)
// goog.inherits(SubClass, SuperClass)
// goog$inherits(SubClass, SuperClass)
// SubClass.mixin(SuperClass.prototype)
// goog.mixin(SubClass.prototype, SuperClass.prototype)
// goog$mixin(SubClass.prototype, SuperClass.prototype)
if (callNode.getChildCount() == 2 &&
callName.getType() == Token.GETPROP) {
// SubClass.inherits(SuperClass)
subclass = callName.getFirstChild();
} else if (callNode.getChildCount() == 3) {
// goog.inherits(SubClass, SuperClass)
subclass = callName.getNext();
}
// bail out if either of the side of the "inherits"
// isn't a real class name. This prevents us from
// doing something weird in cases like:
// goog.inherits(MySubClass, cond ? SuperClass1 : BaseClass2)
if (subclass != null &&
subclass.isUnscopedQualifiedName() &&
superclass.isUnscopedQualifiedName()) {
// make sure to strip the prototype off of the nodes
// to normalize for goog.mixin
return new SubclassRelationship(
type,
stripPrototype(subclass),
stripPrototype(superclass));
}
}
return null;
}
/**
* Determines whether the given node is a class-defining name, like
* "inherits" or "mixin."
* @return The type of class-defining name, or null.
*/
private SubclassType typeofClassDefiningName(Node callName) {
// Check if the method name matches one of the class-defining methods.
String methodName = null;
if (callName
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.getType() == Token.GETPROP) {
methodName = callName.getLastChild().getString();
} else if (callName.getType() == Token.NAME) {
String name = callName.getString();
int dollarIndex = name.lastIndexOf('$');
if (dollarIndex != -1) {
methodName = name.substring(dollarIndex + 1);
}
}
if (methodName != null) {
if (methodName.equals("inherits")) {
return SubclassType.INHERITS;
} else if (methodName.equals("mixin")) {
return SubclassType.MIXIN;
}
}
return null;
}
@Override
public boolean isSuperClassReference(String propertyName) {
return "superClass_".equals(propertyName);
}
/**
* Given a qualified name node, strip "prototype" off the end.
*
* Examples of this transformation:
* a.b.c => a.b.c
* a.b.c.prototype => a.b.c
*/
private Node stripPrototype(Node qualifiedName) {
if (qualifiedName.getType() == Token.GETPROP &&
qualifiedName.getLastChild().getString().equals("prototype")) {
return qualifiedName.getFirstChild();
}
return qualifiedName;
}
/**
* Exctracts X from goog.provide('X'), if the applied Node is goog.
*
* @return The extracted class name, or null.
*/
@Override
public String extractClassNameIfProvide(Node node, Node parent){
return extractClassNameIfGoog(node, parent, "goog.provide");
}
/**
* Exctracts X from goog.require('X'), if the applied Node is goog.
*
* @return The extracted class name, or null.
*/
@Override
public String extractClassNameIfRequire(Node node, Node parent){
return extractClassNameIfGoog(node, parent, "goog.require");
}
private static String extractClassNameIfGoog(Node node, Node parent,
String functionName){
String className = null;
if (NodeUtil.isExprCall(parent)) {
Node callee = node.getFirstChild();
if (callee != null && callee.getType() == Token.GETPROP) {
String qualifiedName = callee
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>.getQualifiedName();
if ((functionName).equals(qualifiedName)) {
className = callee.getNext().getString();
}
}
}
return className;
}
/**
* Use closure's implementation.
* @return closure's function name for exporting properties.
*/
@Override
public String getExportPropertyFunction() {
return "goog.exportProperty";
}
/**
* Use closure's implementation.
* @return closure's function name for exporting symbols.
*/
@Override
public String getExportSymbolFunction() {
return "goog.exportSymbol";
}
@Override
public List<String> identifyTypeDeclarationCall(Node n) {
Node callName = n.getFirstChild();
if ("goog.addDependency".equals(callName.getQualifiedName()) &&
n.getChildCount() >= 3) {
Node typeArray = callName.getNext().getNext();
if (typeArray.getType() == Token.ARRAYLIT) {
List<String> typeNames = Lists.newArrayList();
for (Node name = typeArray.getFirstChild(); name != null;
name = name.getNext()) {
if (name.getType() == Token.STRING) {
typeNames.add(name.getString());
}
}
return typeNames;
}
}
return null;
}
@Override
public String identifyTypeDefAssign(Node n) {
Node firstChild = n.getFirstChild();
int type = n.getType();
if (type == Token.ASSIGN) {
if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) {
return firstChild.getQualifiedName();
}
} else if (type == Token.VAR && firstChild.hasChildren()) {
if (TYPEDEF_NAME.equals(
firstChild.getFirstChild().getQualifiedName())) {
return firstChild.getString();
}
}
return null;
}
@Override
public String getAbstractMethodName() {
return "goog.abstractMethod";
}
@Override
public String getSingletonGetterClassName(Node callNode) {
Node callArg = callNode.getFirstChild();
String callName = callArg.getQualifiedName();
// Use both the original name and the post-CollapseProperties name.
if (!("goog.addSingletonGetter".equals(callName) ||
"goog$add
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>SingletonGetter".equals(callName)) ||
callNode.getChildCount() != 2) {
return null;
}
return callArg.getNext().getQualifiedName();
}
@Override
public void applySingletonGetter(FunctionType functionType,
FunctionType getterType, ObjectType objectType) {
functionType.defineDeclaredProperty("getInstance", getterType, false);
functionType.defineDeclaredProperty("instance_", objectType, false);
}
@Override
public String getGlobalObject() {
return "goog.global";
}
private final Set<String> propertyTestFunctions = ImmutableSet.of(
"goog.isDef", "goog.isNull", "goog.isDefAndNotNull",
"goog.isString", "goog.isNumber", "goog.isBoolean",
"goog.isFunction", "goog.isArray", "goog.isObject");
@Override
public boolean isPropertyTestFunction(Node call) {
Preconditions.checkArgument(call.getType() == Token.CALL);
return propertyTestFunctions.contains(
call.getFirstChild().getQualifiedName());
}
@Override
public ObjectLiteralCast getObjectLiteralCast(NodeTraversal t,
Node callNode) {
Preconditions.checkArgument(callNode.getType() == Token.CALL);
Node callName = callNode.getFirstChild();
if (!"goog.reflect.object".equals(callName.getQualifiedName()) ||
callName.getChildCount() != 2) {
return null;
}
Node typeNode = callName.getNext();
if (!typeNode.isQualifiedName()) {
return null;
}
Node objectNode = typeNode.getNext();
if (objectNode.getType() != Token.OBJECTLIT) {
t.getCompiler().report(JSError.make(t.getSourceName(), callNode,
OBJECTLIT_EXPECTED));
return null;
}
return new ObjectLiteralCast(typeNode.getQualifiedName(),
typeNode.getNext());
}
@Override
public boolean isOptionalParameter(Node parameter) {
return false;
}
@Override
public boolean isVarArgsParameter(Node parameter) {
return false;
}
@Override
public boolean isPrivate(String name) {
return false;
}
@Override
public Collection<AssertionFunctionSpec> getAssertionFunctions() {
return ImmutableList.<AssertionFunctionSpec>
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>is_namespace";
case IS_DISPATCHER: return "is_dispatcher";
case DIRECTIVES: return "directives";
case DIRECT_EVAL: return "direct_eval";
default:
Kit.codeBug();
}
return null;
}
private static class NumberNode extends Node {
private static final long serialVersionUID = 1L;
NumberNode(double number) {
super(Token.NUMBER);
this.number = number;
}
public NumberNode(double number, int lineno, int charno) {
super(Token.NUMBER, lineno, charno);
this.number = number;
}
@Override
public double getDouble() {
return this.number;
}
@Override
public void setDouble(double d) {
this.number = d;
}
@Override
public boolean isEquivalentTo(Node node) {
return (node instanceof NumberNode
&& getDouble() == ((NumberNode) node).getDouble());
}
private double number;
}
private static class StringNode extends Node {
private static final long serialVersionUID = 1L;
StringNode(int type, String str) {
super(type);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
StringNode(int type, String str, int lineno, int charno) {
super(type, lineno, charno);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
/**
* returns the string content.
* @return non null.
*/
@Override
public String getString() {
return this.str;
}
/**
* sets the string content.
* @param str the new value. Non null.
*/
@Override
public void setString(String str) {
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
@Override
public boolean isEquivalentTo(Node node) {
return (node instanceof StringNode &&
this.str.equals(((StringNode) node).str));
}
/**
* If the property is not defined, this was not a quoted key.
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> The
* QUOTED_PROP int property is only assigned to STRING tokens used as
* object lit keys.
* @return true if this was a quoted string key in an object literal.
*/
@Override
public boolean isQuotedString() {
return getBooleanProp(QUOTED_PROP);
}
/**
* This should only be called for STRING nodes created in object lits.
*/
@Override
public void setQuotedString() {
putBooleanProp(QUOTED_PROP, true);
}
private String str;
}
// PropListItems are immutable so that they can be shared.
private static class PropListItem implements Serializable {
private static final long serialVersionUID = 1L;
final PropListItem next;
final int type;
final int intValue;
final Object objectValue;
PropListItem(int type, int intValue, PropListItem next) {
this(type, intValue, null, next);
}
PropListItem(int type, Object objectValue, PropListItem next) {
this(type, 0, objectValue, next);
}
PropListItem(
int type, int intValue, Object objectValue, PropListItem next) {
this.type = type;
this.intValue = intValue;
this.objectValue = objectValue;
this.next = next;
}
}
public Node(int nodeType) {
type = nodeType;
parent = null;
sourcePosition = -1;
}
public Node(int nodeType, Node child) {
Preconditions.checkArgument(child.parent == null,
"new child has existing parent");
Preconditions.checkArgument(child.next == null,
"new child has existing sibling");
type = nodeType;
parent = null;
first = last = child;
child.next = null;
child.parent = this;
sourcePosition = -1;
}
public Node(int nodeType, Node left, Node right) {
Preconditions.checkArgument(left.parent == null,
"first new child has existing parent");
Preconditions.checkArgument(left.next == null,
"first new child has existing sibling");
Preconditions.checkArgument(right.parent == null,
"second new child has existing parent");
Preconditions.checkArgument(right.next == null,
"second
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> Token.STRING) {
throw new IllegalStateException(
"String node not created with Node.newString");
} else {
throw new UnsupportedOperationException(this + " is not a string node");
}
}
@Override
public String toString() {
return toString(true, true, true);
}
public String toString(
boolean printSource,
boolean printAnnotations,
boolean printType) {
if (Token.printTrees) {
StringBuilder sb = new StringBuilder();
toString(sb, printSource, printAnnotations, printType);
return sb.toString();
}
return String.valueOf(type);
}
private void toString(
StringBuilder sb,
boolean printSource,
boolean printAnnotations,
boolean printType) {
if (Token.printTrees) {
sb.append(Token.name(type));
if (this instanceof StringNode) {
sb.append(' ');
sb.append(getString());
} else if (type == Token.FUNCTION) {
sb.append(' ');
// In the case of JsDoc trees, the first child is often not a string
// which causes exceptions to be thrown when calling toString or
// toStringTree.
if (first.getType() == Token.STRING) {
sb.append(first.getString());
}
} else if (this instanceof ScriptOrFnNode) {
ScriptOrFnNode sof = (ScriptOrFnNode) this;
if (this instanceof FunctionNode) {
FunctionNode fn = (FunctionNode) this;
sb.append(' ');
sb.append(fn.getFunctionName());
}
if (printSource) {
sb.append(" [source name: ");
sb.append(sof.getSourceName());
sb.append("] [encoded source length: ");
sb.append(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart());
sb.append("] [base line: ");
sb.append(sof.getBaseLineno());
sb.append("] [end line: ");
sb.append(sof.getEndLineno());
sb.append(']');
}
} else if (type == Token.NUMBER) {
sb.append(' ');
sb.append(getDouble());
}
if (printSource) {
int lineno = getLineno();
if (lineno != -1) {
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> nodes's children.
* The iterator does not support the optional operation
* {@link Iterator#remove()}.</p>
*
* <p>To iterate over a node's siblings, one can write</p>
* <pre>Node n = ...;
* for (Node child : n.children()) { ...</pre>
*/
public Iterable<Node> children() {
if (first == null) {
return Collections.emptySet();
} else {
return new SiblingNodeIterable(first);
}
}
/**
* <p>Return an iterable object that iterates over this nodes's siblings.
* The iterator does not support the optional operation
* {@link Iterator#remove()}.</p>
*
* <p>To iterate over a node's siblings, one can write</p>
* <pre>Node n = ...;
* for (Node sibling : n.siblings()) { ...</pre>
*/
public Iterable<Node> siblings() {
return new SiblingNodeIterable(this);
}
/**
* @see Node#siblings()
*/
private static final class SiblingNodeIterable
implements Iterable<Node>, Iterator<Node> {
private final Node start;
private Node current;
private boolean used;
SiblingNodeIterable(Node start) {
this.start = start;
this.current = start;
this.used = false;
}
public Iterator<Node> iterator() {
if (!used) {
used = true;
return this;
} else {
// We have already used the current object as an iterator;
// we must create a new SiblingNodeIterable based on this
// iterable's start node.
//
// Since the primary use case for Node.children is in for
// loops, this branch is extremely unlikely.
return (new SiblingNodeIterable(start)).iterator();
}
}
public boolean hasNext() {
return current != null;
}
public Node next() {
if (current == null) {
throw new NoSuchElementException();
}
try {
return current;
} finally {
current = current.getNext();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// ==========================================================================
// Accessors
public Node getParent() {
return parent;
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>BREAK: return "break";
case Token.CONTINUE: return "continue";
case Token.VAR: return "var";
case Token.WITH: return "with";
case Token.CATCH: return "catch";
case Token.FINALLY: return "finally";
case Token.RESERVED: return "reserved";
case Token.NOT: return "not";
case Token.VOID: return "void";
case Token.BLOCK: return "block";
case Token.ARRAYLIT: return "arraylit";
case Token.OBJECTLIT: return "objectlit";
case Token.LABEL: return "label";
case Token.TARGET: return "target";
case Token.LOOP: return "loop";
case Token.EXPR_VOID: return "expr_void";
case Token.EXPR_RESULT: return "expr_result";
case Token.JSR: return "jsr";
case Token.SCRIPT: return "script";
case Token.EMPTY: return "empty";
case Token.GET_REF: return "get_ref";
case Token.REF_SPECIAL: return "ref_special";
}
return "<unknown="+token+">";
}
/** Returns true if this node is equivalent semantically to another */
public boolean isEquivalentTo(Node node) {
if (type == Token.ARRAYLIT) {
try {
int[] indices1 = (int[]) getProp(Node.SKIP_INDEXES_PROP);
int[] indices2 = (int[]) node.getProp(Node.SKIP_INDEXES_PROP);
if (indices1 == null) {
if (indices2 != null) {
return false;
}
} else if (indices2 == null) {
return false;
} else if (indices1.length != indices2.length) {
return false;
} else {
for (int i = 0; i < indices1.length; i++) {
if (indices1[i] != indices2[i]) {
return false;
}
}
}
} catch (Exception e) {
return false;
}
} else if (type == Token.INC || type == Token.DEC) {
int post1 = this.getIntProp(INCRDE
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>);
}
/**
* Returns whether this is a synthetic block that should not be considered
* a real source block.
*/
public boolean wasEmptyNode() {
return getBooleanProp(EMPTY_BLOCK);
}
/**
* Marks this function or constructor call node as having no side effects.
* This property is only meaningful for {@link Token#CALL} and
* {@link Token#NEW} nodes.
*/
public void setIsNoSideEffectsCall() {
Preconditions.checkArgument(
getType() == Token.CALL || getType() == Token.NEW,
"setIsNoSideEffectsCall only supports CALL and NEW nodes, got " +
Token.name(getType()));
putBooleanProp(NO_SIDE_EFFECTS_CALL, true);
}
/**
* Returns true if this node is a function or constructor call that
* has no side effects.
*/
public boolean isNoSideEffectsCall() {
return getBooleanProp(NO_SIDE_EFFECTS_CALL);
}
/**
* This should only be called for STRING nodes created in object lits.
*/
public boolean isQuotedString() {
return false;
}
/**
* This should only be called for STRING nodes created in object lits.
*/
public void setQuotedString() {
Kit.codeBug();
}
static class NodeMismatch {
final Node nodeA;
final Node nodeB;
NodeMismatch(Node nodeA, Node nodeB) {
this.nodeA = nodeA;
this.nodeB = nodeB;
}
@Override
public boolean equals(Object object) {
if (object instanceof NodeMismatch) {
NodeMismatch that = (NodeMismatch) object;
return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(nodeA, nodeB);
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1997-1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Bob Jervis
* Google Inc.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU General Public License Version 2 or later (the "GPL"), in which
* case the provisions of the GPL are applicable instead of those above. If
* you wish to allow use of your version of this file only under the terms of
* the GPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replacing
* them with the notice and other provisions required by the GPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* ***** END LICENSE BLOCK ***** */
package com.google.javascript.rhino.jstype;
import static com.google.javascript.rhino.jstype.TernaryValue.FALSE;
import static com.google.javascript.rhino.jstype.TernaryValue.UNKNOWN;
/**
* Number type.
*
*/
public class NumberType extends ValueType {
private static final long serialVersionUID = 1L;
NumberType(JSTypeRegistry registry) {
super(registry);
}
@
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Override
public boolean isNullable() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isUnknownType() || that.isSubtype(
getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) {
return UNKNOWN;
}
return FALSE;
}
@Override
public boolean isNumberValueType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
// TODO(user): Revisit this for ES4, which is stricter.
return true;
}
@Override
public String toString() {
return "number";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNumberType();
}
@Override
public JSType autoboxesTo() {
return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE);
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>(JSTypeRegistry registry, FunctionType constructor,
boolean isNativeType) {
super(registry, null, null, isNativeType);
Preconditions.checkNotNull(constructor);
this.constructor = constructor;
}
@Override
public String getReferenceName() {
return getConstructor().getReferenceName();
}
@Override
public boolean hasReferenceName() {
return getConstructor().hasReferenceName();
}
@Override
public ObjectType getImplicitPrototype() {
return getConstructor().getPrototype();
}
@Override
public FunctionType getConstructor() {
return constructor;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
boolean inExterns) {
ObjectType proto = getImplicitPrototype();
if (proto != null && proto.hasOwnDeclaredProperty(name)) {
return false;
}
return super.defineProperty(name, type, inferred, inExterns);
}
@Override
public String toString() {
if (constructor.hasReferenceName()) {
return constructor.getReferenceName();
} else {
return super.toString();
}
}
@Override
boolean isTheObjectType() {
return getConstructor().isNative() && "Object".equals(getReferenceName());
}
@Override
public boolean isInstanceType() {
return true;
}
@Override
public boolean isArrayType() {
return getConstructor().isNative() && "Array".equals(getReferenceName());
}
@Override
public boolean isStringObjectType() {
return getConstructor().isNative() && "String".equals(getReferenceName());
}
@Override
public boolean isBooleanObjectType() {
return getConstructor().isNative() && "Boolean".equals(getReferenceName());
}
@Override
public boolean isNumberObjectType() {
return getConstructor().isNative() && "Number".equals(getReferenceName());
}
@Override
public boolean isDateType() {
return getConstructor().isNative() && "Date".equals(getReferenceName());
}
@Override
public boolean isRegexpType() {
return getConstructor().isNative() && "RegExp".equals(getReferenceName());
}
@Override
public boolean isNominalType() {
return hasReferenceName();
}
@Override
public boolean isEquivalentTo(JSType that) {
if (this == that)
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
return true;
} else if (this.isNominalType()) {
ObjectType thatObj = ObjectType.cast(that);
if (thatObj != null && thatObj.isNominalType()) {
return getReferenceName().equals(thatObj.getReferenceName());
}
}
return false;
}
/**
* If this is equal to a NamedType object, its hashCode must be equal
* to the hashCode of the NamedType object.
*/
@Override
public int hashCode() {
if (hasReferenceName()) {
return getReferenceName().hashCode();
} else {
return super.hashCode();
}
}
@Override
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return getConstructor().getImplementedInterfaces();
}
// The owner will always be a resolved type, so there's no need to set
// the constructor in resolveInternal.
// (it would lead to infinite loops if we did).
// JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope);
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>1L;
NullType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNullType() {
return true;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return false;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public JSType restrictByNotNullOrUndefined() {
return registry.getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isNullType() || that.isVoidType()) {
return TRUE;
}
if (that.isUnknownType() || that.isNullable()) {
return UNKNOWN;
}
return FALSE;
}
@Override
public String toString() {
return "null";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.FALSE;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNullType();
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.collect.ImmutableSet;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Node;
/**
* A compiler pass to run various peephole optimizations (e.g. constant folding,
* some useless code removal, some minimizations).
*
* @author dcc@google.com (Devin Coughlin)
*/
class PeepholeOptimizationsPass extends AbstractPostOrderCallback
implements CompilerPass {
private AbstractCompiler compiler;
private ImmutableSet<AbstractPeepholeOptimization> peepholeOptimizations;
PeepholeOptimizationsPass(AbstractCompiler compiler,
ImmutableSet<AbstractPeepholeOptimization> optimizations) {
this.compiler = compiler;
this.peepholeOptimizations = optimizations;
}
/**
* Creates a peephole optimization pass that runs the given
* optimizations.
*/
PeepholeOptimizationsPass(AbstractCompiler compiler,
AbstractPeepholeOptimization... optimizations) {
this(compiler, ImmutableSet.copyOf(optimizations));
}
public AbstractCompiler getCompiler() {
return compiler;
}
@Override
public void process(Node externs, Node root) {
NodeTraversal t = new NodeTraversal(compiler, this);
beginTraversal(t);
t.traverse(root);
endTraversal(t);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
Node currentVersionOfNode = n;
boolean somethingChanged =
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> ownerFunction,
ObjectType implicitPrototype, boolean isNative) {
super(registry, null /* has no class name */, implicitPrototype,
isNative);
this.ownerFunction = ownerFunction;
}
FunctionPrototypeType(JSTypeRegistry registry, FunctionType ownerFunction,
ObjectType implicitPrototype) {
this(registry, ownerFunction, implicitPrototype, false);
}
@Override
public String getReferenceName() {
if (ownerFunction == null) {
return "{...}.prototype";
} else {
return ownerFunction.getReferenceName() + ".prototype";
}
}
@Override
public boolean hasReferenceName() {
return ownerFunction != null && ownerFunction.hasReferenceName();
}
@Override
public boolean isFunctionPrototypeType() {
return true;
}
public FunctionType getOwnerFunction() {
return ownerFunction;
}
@Override
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return getOwnerFunction().getImplementedInterfaces();
}
// The owner will always be a resolved type, so there's no need to set
// the ownerFunction in resolveInternal.
// (it would lead to infinite loops if we did).
// JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope);
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> =
createUnionType(NUMBER_OBJECT_TYPE, NUMBER_TYPE);
registerNativeType(
JSTypeNative.NUMBER_VALUE_OR_OBJECT_TYPE, NUMBER_VALUE_OR_OBJECT_TYPE);
// unknown function type, i.e. (?...) -> ?
FunctionType U2U_FUNCTION_TYPE =
createFunctionType(UNKNOWN_TYPE, true, UNKNOWN_TYPE);
registerNativeType(JSTypeNative.U2U_FUNCTION_TYPE, U2U_FUNCTION_TYPE);
// unknown constructor type, i.e. (?...) -> ? with the NoObject type
// as instance type
FunctionType U2U_CONSTRUCTOR_TYPE =
// This is equivalent to
// createConstructorType(UNKNOWN_TYPE, true, UNKNOWN_TYPE), but,
// in addition, overrides getInstanceType() to return the NoObject type
// instead of a new anonymous object.
new FunctionType(this, "Function", null,
createArrowType(
createParametersWithVarArgs(UNKNOWN_TYPE),
UNKNOWN_TYPE),
NO_OBJECT_TYPE, null, true, true) {
private static final long serialVersionUID = 1L;
@Override public FunctionType getConstructor() {
return registry.getNativeFunctionType(
JSTypeNative.FUNCTION_FUNCTION_TYPE);
}
};
// The U2U_CONSTRUCTOR is weird, because it's the supertype of its
// own constructor.
registerNativeType(JSTypeNative.U2U_CONSTRUCTOR_TYPE, U2U_CONSTRUCTOR_TYPE);
registerNativeType(
JSTypeNative.FUNCTION_INSTANCE_TYPE, U2U_CONSTRUCTOR_TYPE);
FUNCTION_FUNCTION_TYPE.setInstanceType(U2U_CONSTRUCTOR_TYPE);
U2U_CONSTRUCTOR_TYPE.setImplicitPrototype(FUNCTION_PROTOTYPE);
// least function type, i.e. (All...) -> NoType
FunctionType LEAST_FUNCTION_TYPE =
createFunctionType(NO_TYPE, true, ALL_TYPE);
registerNativeType(JSTypeNative.LEAST_FUNCTION_TYPE, LEAST_FUNCTION_TYPE);
// the 'this' object in the global scope
ObjectType GLOBAL_THIS = createObjectType("global this", null,
UNKNOWN_TYPE /* to be resolved later */);
registerNativeType(JSTypeNative
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> a function is not specified
return getNativeType(UNKNOWN_TYPE);
case Token.VOID: // Only allowed in the return value of a function.
return getNativeType(VOID_TYPE);
case Token.STRING:
JSType namedType = getType(scope, n.getString(), sourceName,
n.getLineno(), n.getCharno());
if (forgiving) {
namedType.forgiveUnknownNames();
}
if (resolveMode != ResolveMode.LAZY_NAMES) {
namedType = namedType.resolveInternal(reporter, scope);
}
if ((namedType instanceof ObjectType) &&
!(enumTypeNames.contains(n.getString()))) {
Node typeList = n.getFirstChild();
if (typeList != null &&
("Array".equals(n.getString()) ||
"Object".equals(n.getString()))) {
JSType parameterType =
createFromTypeNodesInternal(
typeList.getLastChild(), sourceName, scope, false);
namedType = new ParameterizedType(
this, (ObjectType) namedType, parameterType);
if (typeList.hasMoreThanOneChild()) {
JSType indexType =
createFromTypeNodesInternal(
typeList.getFirstChild(), sourceName, scope, false);
namedType = new IndexedType(
this, (ObjectType) namedType, indexType);
}
}
return createDefaultObjectUnion(namedType);
} else {
return namedType;
}
case Token.FUNCTION:
ObjectType thisType = null;
Node current = n.getFirstChild();
if (current.getType() == Token.THIS) {
Node thisNode = current.getFirstChild();
thisType =
ObjectType.cast(
createFromTypeNodesInternal(
thisNode, sourceName, scope, false)
.restrictByNotNullOrUndefined());
if (thisType == null) {
reporter.warning(
ScriptRuntime.getMessage0("msg.jsdoc.function.thisnotobject"),
sourceName, thisNode.getLineno(), "", thisNode.getCharno());
}
current = current.getNext();
}
FunctionParamBuilder paramBuilder = new FunctionParamBuilder(this);
if (current.getType() == Token.LP) {
Node args = current.getFirstChild();
for (Node arg = current.getFirst
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> typeA.isEquivalentTo(typeB);
}
@Override
public boolean equals(Object jsType) {
return (jsType instanceof JSType) ?
isEquivalentTo((JSType) jsType) : false;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
/**
* This predicate is used to test whether a given type can appear in a
* 'Int32' context. This context includes, for example, the operands of a
* bitwise or operator. Since we do not currently support integer types,
* this is a synonym for {@code Number}.
*/
public final boolean matchesInt32Context() {
return matchesNumberContext();
}
/**
* This predicate is used to test whether a given type can appear in a
* 'Uint32' context. This context includes the right-hand operand of a shift
* operator.
*/
public final boolean matchesUint32Context() {
return matchesNumberContext();
}
/**
* This predicate is used to test whether a given type can appear in a
* numeric context, such as an operand of a multiply operator.
*/
public boolean matchesNumberContext() {
return false;
}
/**
* This predicate is used to test whether a given type can appear in a
* {@code String} context, such as an operand of a string concat (+) operator.
*
* All types have at least the potential for converting to {@code String}.
* When we add externally defined types, such as a browser OM, we may choose
* to add types that do not automatically convert to {@code String}.
*/
public boolean matchesStringContext() {
return false;
}
/**
* This predicate is used to test whether a given type can appear in an
* {@code Object} context, such as the expression in a with statement.
*
* Most types we will encounter, except notably {@code null}, have at least
* the potential for converting to {@code Object}. Host defined objects can
* get peculiar.
*/
public boolean matchesObjectContext() {
return false;
}
/**
* Coerces this type to an Object type, then gets the type of the property
* whose name is given.
*
* Unlike {@
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>that.isUnknownType()) {
return !this.isEquivalentTo(that);
}
// otherwise, they're different iff one is unknown and the other is not.
return this.isUnknownType() ^ that.isUnknownType();
}
/**
* A generic implementation meant to be used as a helper for common subtyping
* cases.
*/
static boolean isSubtype(JSType thisType, JSType thatType) {
// unknown
if (thatType.isUnknownType()) {
return true;
}
// equality
if (thisType.isEquivalentTo(thatType)) {
return true;
}
// all type
if (thatType.isAllType()) {
return true;
}
// unions
if (thatType instanceof UnionType) {
UnionType union = (UnionType)thatType;
for (JSType element : union.alternates) {
if (thisType.isSubtype(element)) {
return true;
}
}
}
// named types
if (thatType instanceof NamedType) {
return thisType.isSubtype(((NamedType)thatType).referencedType);
}
return false;
}
/**
* Visit this type with the given visitor.
* @see com.google.javascript.rhino.jstype.Visitor
* @return the value returned by the visitor
*/
public abstract <T> T visit(Visitor<T> visitor);
/**
* Force this type to resolve, even if the registry is in a lazy
* resolving mode.
* @see #resolve
*/
public final JSType forceResolve(ErrorReporter t, StaticScope<JSType> scope) {
ResolveMode oldResolveMode = registry.getResolveMode();
registry.setResolveMode(ResolveMode.IMMEDIATE);
JSType result = resolve(t, scope);
registry.setResolveMode(oldResolveMode);
return result;
}
/**
* Resolve this type in the given scope.
*
* The returned value must be equal to {@code this}, as defined by
* {@link #isEquivalentTo}. It may or may not be the same object. This method
* may modify the internal state of {@code this}, as long as it does
* so in a way that preserves Object equality.
*
* For efficiency,
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> arrow type from the complex
* {@link FunctionType} that models JavaScript's notion of functions.
*
*
*/
final class ArrowType extends JSType {
private static final long serialVersionUID = 1L;
final Node parameters;
JSType returnType;
// Whether the return type is inferred.
final boolean returnTypeInferred;
ArrowType(JSTypeRegistry registry, Node parameters,
JSType returnType) {
this(registry, parameters, returnType, false);
}
ArrowType(JSTypeRegistry registry, Node parameters,
JSType returnType, boolean returnTypeInferred) {
super(registry);
this.parameters = parameters == null ?
registry.createParametersWithVarArgs(getNativeType(UNKNOWN_TYPE)) :
parameters;
this.returnType = returnType == null ?
getNativeType(UNKNOWN_TYPE) : returnType;
this.returnTypeInferred = returnTypeInferred;
}
@Override
public boolean isSubtype(JSType other) {
if (!(other instanceof ArrowType)) {
return false;
}
ArrowType that = (ArrowType) other;
// this.returnType <: that.returnType (covariant)
if (!this.returnType.isSubtype(that.returnType)) {
return false;
}
// that.paramType[i] <: this.paramType[i] (contravariant)
// TODO(nicksantos): This is incorrect. It should be invariant.
// Follow up with closure team on how to fix this without everyone
// hating on us.
Node thisParam = parameters.getFirstChild();
Node thatParam = that.parameters.getFirstChild();
while (thisParam != null && thatParam != null) {
JSType thisParamType = thisParam.getJSType();
if (thisParamType != null) {
JSType thatParamType = thatParam.getJSType();
if (thatParamType == null ||
!thatParamType.isSubtype(thisParamType)) {
return false;
}
}
boolean thisIsVarArgs = thisParam.isVarArgs();
boolean thatIsVarArgs = thatParam.isVarArgs();
// don't advance if we have variable arguments
if (!thisIsVarArgs) {
thisParam = thisParam.getNext();
}
if (!thatIsVarArgs) {
thatParam = that
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>Param.getNext();
}
// both var_args indicates the end
if (thisIsVarArgs && thatIsVarArgs) {
thisParam = null;
thatParam = null;
}
}
// Right now, the parser's type system doesn't have a good way
// to model optional arguments.
//
// Suppose we have
// function f(number, number) {}
// function g(number) {}
// If the second arg of f is optional, then f is a subtype of g,
// but g is not a subtype of f.
// If the second arg of f is required, then g is a subtype of f,
// but f is not a subtype of g.
//
// Until we model optional params, let's just punt on this.
// If one type has more arguments than the other, we won't check them.
//
// NOTE(nicksantos): This is described in Draft 2 of the ES4 spec,
// Section 3.4.6: Subtyping Function Types. It seems really
// strange but I haven't thought a lot about the implementation.
return true;
}
/**
* @return True if our parameter spec is equal to {@code that}'s parameter
* spec.
*/
boolean hasEqualParameters(ArrowType that) {
Node thisParam = parameters.getFirstChild();
Node otherParam = that.parameters.getFirstChild();
while (thisParam != null && otherParam != null) {
JSType thisParamType = thisParam.getJSType();
JSType otherParamType = otherParam.getJSType();
if (thisParamType != null) {
// Both parameter lists give a type for this param, it should be equal
if (otherParamType != null &&
!thisParamType.isEquivalentTo(otherParamType)) {
return false;
}
} else {
if (otherParamType != null) {
return false;
}
}
thisParam = thisParam.getNext();
otherParam = otherParam.getNext();
}
// One of the parameters is null, so the types are only equal if both
// parameter lists are null (they are equal).
return thisParam == otherParam;
}
@Override
public boolean isEquivalentTo(JSType object) {
// Please
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> keep this method in sync with the hashCode() method below.
if (!(object instanceof ArrowType)) {
return false;
}
ArrowType that = (ArrowType) object;
if (!returnType.isEquivalentTo(that.returnType) ||
returnTypeInferred != that.returnTypeInferred) {
return false;
}
return hasEqualParameters(that);
}
@Override
public int hashCode() {
int hashCode = 0;
if (returnType != null) {
hashCode += returnType.hashCode();
}
if (returnTypeInferred) {
hashCode += 1;
}
if (parameters != null) {
Node param = parameters.getFirstChild();
while (param != null) {
JSType paramType = param.getJSType();
if (paramType != null) {
hashCode += paramType.hashCode();
}
param = param.getNext();
}
}
return hashCode;
}
@Override
public JSType getLeastSupertype(JSType that) {
throw new UnsupportedOperationException();
}
@Override
public JSType getGreatestSubtype(JSType that) {
throw new UnsupportedOperationException();
}
@Override
public TernaryValue testForEquality(JSType that) {
throw new UnsupportedOperationException();
}
@Override
public <T> T visit(Visitor<T> visitor) {
throw new UnsupportedOperationException();
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.TRUE;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
returnType = safeResolve(returnType, t, scope);
if (parameters != null) {
for (Node paramNode = parameters.getFirstChild();
paramNode != null; paramNode = paramNode.getNext()) {
paramNode.setJSType(paramNode.getJSType().resolve(t, scope));
}
}
return this;
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>ERROR_FUNCTION_TYPE;
protected ObjectType TYPE_ERROR_TYPE;
protected FunctionType U2U_CONSTRUCTOR_TYPE;
protected FunctionType U2U_FUNCTION_TYPE;
protected ObjectType UNKNOWN_TYPE;
protected JSType URI_ERROR_FUNCTION_TYPE;
protected ObjectType URI_ERROR_TYPE;
protected JSType VOID_TYPE;
protected int NATIVE_PROPERTIES_COUNT;
@Override
protected void setUp() throws Exception {
super.setUp();
errorReporter = new TestErrorReporter(null, null);
registry = new JSTypeRegistry(errorReporter);
initTypes();
}
protected void initTypes() {
ALL_TYPE =
registry.getNativeType(JSTypeNative.ALL_TYPE);
NO_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_OBJECT_TYPE);
NO_TYPE =
registry.getNativeObjectType(JSTypeNative.NO_TYPE);
ARRAY_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.ARRAY_FUNCTION_TYPE);
ARRAY_TYPE =
registry.getNativeObjectType(JSTypeNative.ARRAY_TYPE);
BOOLEAN_OBJECT_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.BOOLEAN_OBJECT_FUNCTION_TYPE);
BOOLEAN_OBJECT_TYPE =
registry.getNativeObjectType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
BOOLEAN_TYPE =
registry.getNativeType(JSTypeNative.BOOLEAN_TYPE);
CHECKED_UNKNOWN_TYPE =
registry.getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
DATE_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.DATE_FUNCTION_TYPE);
DATE_TYPE =
registry.getNativeObjectType(JSTypeNative.DATE_TYPE);
ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.ERROR_FUNCTION_TYPE);
ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.ERROR_TYPE);
EVAL_ERROR_FUNCTION_TYPE =
registry.getNativeType(JSTypeNative.EVAL_ERROR_FUNCTION_TYPE);
EVAL_ERROR_TYPE =
registry.getNativeObjectType(JSTypeNative.EVAL_ERROR_TYPE);
FUNCTION_FUNCTION_TYPE =
registry.getNativeFunctionType(JSTypeNative.FUNCTION_FUNCTION_
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> PassFactory factory, String passName) {
factoryList.add(
findPassIndexByName(factoryList, passName), factory);
}
/**
* Find a pass factory with the same name as the given one, and replace it.
*/
final static void replacePassFactory(
List<PassFactory> factoryList, PassFactory factory) {
factoryList.set(
findPassIndexByName(factoryList, factory.getName()), factory);
}
/**
* Throws an exception if no pass with the given name exists.
*/
private static int findPassIndexByName(
List<PassFactory> factoryList, String name) {
for (int i = 0; i < factoryList.size(); i++) {
if (factoryList.get(i).getName().equals(name)) {
return i;
}
}
throw new IllegalArgumentException(
"No factory named '" + name + "' in the factory list");
}
/**
* Find the first pass provider that does not have a delegate.
*/
final PassConfig getBasePassConfig() {
PassConfig current = this;
while (current instanceof PassConfigDelegate) {
current = ((PassConfigDelegate) current).delegate;
}
return current;
}
/**
* Get intermediate state for a running pass config, so it can
* be paused and started again later.
*/
abstract State getIntermediateState();
/**
* Set the intermediate state for a pass config, to restart
* a compilation process that had been previously paused.
*/
abstract void setIntermediateState(State state);
/**
* An implementation of PassConfig that just proxies all its method calls
* into an inner class.
*/
static class PassConfigDelegate extends PassConfig {
private final PassConfig delegate;
PassConfigDelegate(PassConfig delegate) {
super(delegate.options);
this.delegate = delegate;
}
@Override protected List<PassFactory> getChecks() {
return delegate.getChecks();
}
@Override protected List<PassFactory> getOptimizations() {
return delegate.getOptimizations();
}
@Override ScopeCreator getScopeCreator() {
return delegate.getScopeCreator();
}
@Override Scope getTopScope() {
return delegate.getTopScope();
}
@Override State getIntermediateState() {
return delegate.get
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>IntermediateState();
}
@Override void setIntermediateState(State state) {
delegate.setIntermediateState(state);
}
}
/**
* Intermediate state for a running pass configuration.
*/
static class State implements Serializable {
private static final long serialVersionUID = 1L;
final Map<String, Integer> cssNames;
final Set<String> exportedNames;
final CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator;
final VariableMap variableMap;
final VariableMap propertyMap;
final VariableMap anonymousFunctionNameMap;
final VariableMap stringMap;
final FunctionNames functionNames;
State(Map<String, Integer> cssNames, Set<String> exportedNames,
CrossModuleMethodMotion.IdGenerator crossModuleIdGenerator,
VariableMap variableMap, VariableMap propertyMap,
VariableMap anonymousFunctionNameMap,
VariableMap stringMap, FunctionNames functionNames) {
this.cssNames = cssNames;
this.exportedNames = exportedNames;
this.crossModuleIdGenerator = crossModuleIdGenerator;
this.variableMap = variableMap;
this.propertyMap = propertyMap;
this.anonymousFunctionNameMap = anonymousFunctionNameMap;
this.stringMap = stringMap;
this.functionNames = functionNames;
}
}
}
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> arrowType, ObjectType typeOfThis,
String templateTypeName, boolean isConstructor, boolean nativeType) {
super(registry, name,
registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE),
nativeType);
Preconditions.checkArgument(source == null ||
Token.FUNCTION == source.getType());
Preconditions.checkNotNull(arrowType);
this.source = source;
this.kind = isConstructor ? Kind.CONSTRUCTOR : Kind.ORDINARY;
if (isConstructor) {
this.typeOfThis = typeOfThis != null && typeOfThis.isNoObjectType() ?
typeOfThis : new InstanceObjectType(registry, this, nativeType);
} else {
this.typeOfThis = typeOfThis != null ?
typeOfThis :
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
}
this.call = arrowType;
this.templateTypeName = templateTypeName;
}
/** Creates an instance for a function that is an interface. */
private FunctionType(JSTypeRegistry registry, String name, Node source) {
super(registry, name,
registry.getNativeObjectType(JSTypeNative.FUNCTION_INSTANCE_TYPE));
Preconditions.checkArgument(source == null ||
Token.FUNCTION == source.getType());
Preconditions.checkArgument(name != null);
this.source = source;
this.call = new ArrowType(registry, new Node(Token.LP), null);
this.kind = Kind.INTERFACE;
this.typeOfThis = new InstanceObjectType(registry, this);
}
/** Creates an instance for a function that is an interface. */
static FunctionType forInterface(
JSTypeRegistry registry, String name, Node source) {
return new FunctionType(registry, name, source);
}
@Override
public boolean isInstanceType() {
// The universal constructor is its own instance, bizarrely.
return isEquivalentTo(registry.getNativeType(U2U_CONSTRUCTOR_TYPE));
}
@Override
public boolean isConstructor() {
return kind == Kind.CONSTRUCTOR;
}
@Override
public boolean isInterface() {
return kind == Kind.INTERFACE;
}
@Override
public boolean isOrdinaryFunction() {
return kind == Kind.ORDINARY;
}
@Override
public boolean isFunctionType()
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> {
return true;
}
@Override
public boolean canBeCalled() {
return true;
}
public Iterable<Node> getParameters() {
Node n = getParametersNode();
if (n != null) {
return n.children();
} else {
return Collections.emptySet();
}
}
/** Gets an LP node that contains all params. May be null. */
public Node getParametersNode() {
return call.parameters;
}
/** Gets the minimum number of arguments that this function requires. */
public int getMinArguments() {
// NOTE(nicksantos): There are some native functions that have optional
// parameters before required parameters. This algorithm finds the position
// of the last required parameter.
int i = 0;
int min = 0;
for (Node n : getParameters()) {
i++;
if (!n.isOptionalArg() && !n.isVarArgs()) {
min = i;
}
}
return min;
}
/**
* Gets the maximum number of arguments that this function requires,
* or Integer.MAX_VALUE if this is a variable argument function.
*/
public int getMaxArguments() {
Node params = getParametersNode();
if (params != null) {
Node lastParam = params.getLastChild();
if (lastParam == null || !lastParam.isVarArgs()) {
return params.getChildCount();
}
}
return Integer.MAX_VALUE;
}
public JSType getReturnType() {
return call.returnType;
}
public boolean isReturnTypeInferred() {
return call.returnTypeInferred;
}
/** Gets the internal arrow type. For use by subclasses only. */
ArrowType getInternalArrowType() {
return call;
}
/**
* Gets the {@code prototype} property of this function type. This is
* equivalent to {@code (ObjectType) getPropertyType("prototype")}.
*/
public FunctionPrototypeType getPrototype() {
// lazy initialization of the prototype field
if (prototype == null) {
setPrototype(new FunctionPrototypeType(registry, this, null));
}
return prototype;
}
/**
* Sets the prototype, creating the prototype object from the given
* base type.
* @param baseType The base type.
*/
public void
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>ObjectType type : implementedInterfaces) {
registry.registerTypeImplementingInterface(this, type);
}
this.implementedInterfaces = ImmutableList.copyOf(implementedInterfaces);
}
@Override
public boolean hasProperty(String name) {
return super.hasProperty(name) || "prototype".equals(name);
}
@Override
public boolean hasOwnProperty(String name) {
return super.hasOwnProperty(name) || "prototype".equals(name);
}
@Override
public JSType getPropertyType(String name) {
if ("prototype".equals(name)) {
return getPrototype();
} else {
if (!hasOwnProperty(name)) {
if ("call".equals(name)) {
// Define the "call" function lazily.
Node params = getParametersNode();
if (params == null) {
// If there's no params array, don't do any type-checking
// in this CALL function.
defineDeclaredProperty(name,
new FunctionBuilder(registry)
.withReturnType(getReturnType())
.build(),
false);
} else {
params = params.cloneTree();
Node thisTypeNode = Node.newString(Token.NAME, "thisType");
thisTypeNode.setJSType(
registry.createOptionalNullableType(getTypeOfThis()));
params.addChildToFront(thisTypeNode);
thisTypeNode.setOptionalArg(true);
defineDeclaredProperty(name,
new FunctionBuilder(registry)
.withParamsNode(params)
.withReturnType(getReturnType())
.build(),
false);
}
} else if ("apply".equals(name)) {
// Define the "apply" function lazily.
FunctionParamBuilder builder = new FunctionParamBuilder(registry);
// Ecma-262 says that apply's second argument must be an Array
// or an arguments object. We don't model the arguments object,
// so let's just be forgiving for now.
// TODO(nicksantos): Model the Arguments object.
builder.addOptionalParams(
registry.createNullableType(getTypeOfThis()),
registry.createNullableType(
registry.getNativeType(JSTypeNative.OBJECT_TYPE)));
defineDeclaredProperty(name,
new FunctionBuilder(registry)
.withParams(builder)
.withReturnType(getReturnType
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>())
.build(),
false);
}
}
return super.getPropertyType(name);
}
}
@Override
boolean defineProperty(String name, JSType type,
boolean inferred, boolean inExterns) {
if ("prototype".equals(name)) {
ObjectType objType = type.toObjectType();
if (objType != null) {
if (objType.isEquivalentTo(prototype)) {
return true;
}
return setPrototype(
new FunctionPrototypeType(
registry, this, objType, isNativeObjectType()));
} else {
return false;
}
}
return super.defineProperty(name, type, inferred, inExterns);
}
@Override
public boolean isPropertyTypeInferred(String property) {
return "prototype".equals(property) ||
super.isPropertyTypeInferred(property);
}
@Override
public JSType getLeastSupertype(JSType that) {
return supAndInfHelper(that, true);
}
@Override
public JSType getGreatestSubtype(JSType that) {
return supAndInfHelper(that, false);
}
private JSType supAndInfHelper(JSType that, boolean leastSuper) {
// NOTE(nicksantos): When we remove the unknown type, the function types
// form a lattice with the universal constructor at the top of the lattice,
// and the NoObject type at the bottom of the lattice.
//
// When we introduce the unknown type, it's much more difficult to make
// heads or tails of the partial ordering of types, because there's no
// clear hierarchy between the different components (parameter types and
// return types) in the ArrowType.
//
// Rather than make the situation more complicated by introducing new
// types (like unions of functions), we just fallback on the simpler
// approach of using the universal constructor and the AnyObject as
// the supremum and infinum of all function types.
if (isFunctionType() && that.isFunctionType()) {
if (isEquivalentTo(that)) {
return this;
}
// If this is a normal function, look to see if the arguments are equal.
// If they are, we can just take the least supertype (or greatest
// subtype) of the return types.
if
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> or someone defines
// a bad type. Otherwise the loop should always end.
FunctionType ctor = this;
while (true) {
ObjectType maybeSuperInstanceType =
ctor.getPrototype().getImplicitPrototype();
if (maybeSuperInstanceType == null) {
return false;
}
if (maybeSuperInstanceType.isUnknownType()) {
return true;
}
ctor = maybeSuperInstanceType.getConstructor();
if (ctor == null) {
return false;
}
Preconditions.checkState(ctor.isConstructor() || ctor.isInterface());
}
}
/**
* Given a constructor or an interface type and a property, finds the
* top-most superclass that has the property defined (including this
* constructor).
*/
public JSType getTopMostDefiningType(String propertyName) {
Preconditions.checkState(isConstructor() || isInterface());
Preconditions.checkArgument(getPrototype().hasProperty(propertyName));
FunctionType ctor = this;
JSType topInstanceType;
do {
topInstanceType = ctor.getInstanceType();
ctor = ctor.getSuperClassConstructor();
} while (ctor != null && ctor.getPrototype().hasProperty(propertyName));
return topInstanceType;
}
/**
* Two function types are equal if their signatures match. Since they don't
* have signatures, two interfaces are equal if their names match.
*/
@Override
public boolean isEquivalentTo(JSType otherType) {
if (!(otherType instanceof FunctionType)) {
return false;
}
FunctionType that = (FunctionType) otherType;
if (!that.isFunctionType()) {
return false;
}
if (this.isConstructor()) {
if (that.isConstructor()) {
return this == that;
}
return false;
}
if (this.isInterface()) {
if (that.isInterface()) {
return this.getReferenceName().equals(that.getReferenceName());
}
return false;
}
if (that.isInterface()) {
return false;
}
return this.typeOfThis.isEquivalentTo(that.typeOfThis) &&
this.call.isEquivalentTo(that.call);
}
@Override
public int hashCode() {
return isInterface() ? getReferenceName().hashCode() : call.hashCode();
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>
}
public boolean hasEqualCallType(FunctionType otherType) {
return this.call.isEquivalentTo(otherType.call);
}
/**
* Informally, a function is represented by
* {@code function (params): returnType} where the {@code params} is a comma
* separated list of types, the first one being a special
* {@code this:T} if the function expects a known type for {@code this}.
*/
@Override
public String toString() {
if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) {
return "Function";
}
StringBuilder b = new StringBuilder(32);
b.append("function (");
int paramNum = call.parameters.getChildCount();
boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType();
if (hasKnownTypeOfThis) {
b.append("this:");
b.append(typeOfThis.toString());
}
if (paramNum > 0) {
if (hasKnownTypeOfThis) {
b.append(", ");
}
Node p = call.parameters.getFirstChild();
if (p.isVarArgs()) {
appendVarArgsString(b, p.getJSType());
} else {
b.append(p.getJSType().toString());
}
p = p.getNext();
while (p != null) {
b.append(", ");
if (p.isVarArgs()) {
appendVarArgsString(b, p.getJSType());
} else {
b.append(p.getJSType().toString());
}
p = p.getNext();
}
}
b.append("): ");
b.append(call.returnType);
return b.toString();
}
/** Gets the string representation of a var args param. */
private void appendVarArgsString(StringBuilder builder, JSType paramType) {
if (paramType.isUnionType()) {
// Remove the optionalness from the var arg.
paramType = ((UnionType) paramType).getRestrictedUnion(
registry.getNativeType(JSTypeNative.VOID_TYPE));
}
builder.append("...[").append(paramType.toString()).append("]");
}
/**
* A function is a subtype of another if their call
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> methods are related via
* subtyping and {@code this} is a subtype of {@code that} with regard to
* the prototype chain.
*/
@Override
public boolean isSubtype(JSType that) {
if (this.isEquivalentTo(that)) {
return true;
}
if (that.isFunctionType()) {
if (((FunctionType) that).isInterface()) {
// Any function can be assigned to an interface function.
return true;
}
if (this.isInterface()) {
// An interface function cannot be assigned to anything.
return false;
}
// If functionA is a subtype of functionB, then their "this" types
// should be contravariant. However, this causes problems because
// of the way we enforce overrides. Because function(this:SubFoo)
// is not a subtype of function(this:Foo), our override check treats
// this as an error. It also screws up out standard method
// for aliasing constructors. Let's punt on all this for now.
// TODO(nicksantos): fix this.
FunctionType other = (FunctionType) that;
return (this.isConstructor() || other.isConstructor() ||
other.typeOfThis.isSubtype(this.typeOfThis) ||
this.typeOfThis.isSubtype(other.typeOfThis)) &&
this.call.isSubtype(other.call);
}
if (that instanceof UnionType) {
UnionType union = (UnionType) that;
for (JSType element : union.alternates) {
if (this.isSubtype(element)) {
return true;
}
}
}
return getNativeType(JSTypeNative.FUNCTION_PROTOTYPE).isSubtype(that);
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseFunctionType(this);
}
/**
* Gets the type of instance of this function.
* @throws IllegalStateException if this function is not a constructor
* (see {@link #isConstructor()}).
*/
public ObjectType getInstanceType() {
Preconditions.checkState(hasInstanceType());
return typeOfThis;
}
/** Sets the instance type. This should only be used for special native types. */
void setInstanceType(ObjectType instanceType
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS>) {
typeOfThis = instanceType;
}
/**
* Returns whether this function type has an instance type.
*/
public boolean hasInstanceType() {
return isConstructor() || isInterface();
}
/**
* Gets the type of {@code this} in this function.
*/
public ObjectType getTypeOfThis() {
return typeOfThis.isNoObjectType() ?
registry.getNativeObjectType(JSTypeNative.OBJECT_TYPE) : typeOfThis;
}
/**
* Gets the source node or null if this is an unknown function.
*/
public Node getSource() {
return source;
}
/**
* Sets the source node.
*/
public void setSource(Node source) {
this.source = source;
}
/** Adds a type to the list of subtypes for this type. */
private void addSubType(FunctionType subType) {
if (subTypes == null) {
subTypes = Lists.newArrayList();
}
subTypes.add(subType);
}
/**
* Returns a list of types that are subtypes of this type. This is only valid
* for constructor functions, and may be null. This allows a downward
* traversal of the subtype graph.
*/
public List<FunctionType> getSubTypes() {
return subTypes;
}
@Override
public boolean hasCachedValues() {
return prototype != null || super.hasCachedValues();
}
/**
* Gets the template type name.
*/
public String getTemplateTypeName() {
return templateTypeName;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
setResolvedTypeInternal(this);
call = (ArrowType) safeResolve(call, t, scope);
prototype = (FunctionPrototypeType) safeResolve(prototype, t, scope);
typeOfThis = (ObjectType) safeResolve(typeOfThis, t, scope);
boolean changed = false;
ImmutableList.Builder<ObjectType> resolvedInterfaces =
ImmutableList.builder();
for (ObjectType iface : implementedInterfaces) {
ObjectType resolvedIface = (ObjectType) iface.resolve(t, scope);
resolvedInterfaces.add(resolvedIface);
changed |= (resolvedIface != iface);
}
if (changed) {
implementedInterfaces = resolvedInterfaces.build();
}
if
Closure, 148
<FILEB>
<CHANGES>
case Token.VOID:
typeNameString = "undefined";
break;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private final static int UNMAPPED = -1;
<CHANGEE>
<CHANGES>
int id = UNMAPPED;
<CHANGEE>
<CHANGES>
boolean used = false;
}
private class MappingWriter {
<CHANGEE>
<CHANGES>
private String lastSourceFile = null;
private String lastSourceFileEscaped = null;
private int lastLine = 0;
private String lastLineString = String.valueOf(0);
<CHANGEE>
<CHANGES>
private void appendMappingTo(
Mapping m, Appendable out) throws IOException {
<CHANGEE>
<CHANGES>
String sourceFile = m.sourceFile;
<CHANGEE>
<CHANGES>
String escapedSourceFile;
if (lastSourceFile!= sourceFile) { // yes, s1!= s2, not!s1.equals(s2)
lastSourceFile = sourceFile;
lastSourceFileEscaped = escapeString(sourceFile);
}
escapedSourceFile = lastSourceFileEscaped;
out.append(escapedSourceFile);
<CHANGEE>
<CHANGES>
int line = m.originalPosition.getLineNumber();
if (line!= lastLine) {
lastLineString = String.valueOf(line);
}
String lineValue = lastLineString;
out.append(lineValue);
<CHANGEE>
<CHANGES>
out.append(String.valueOf(
m.originalPosition.getCharacterIndex()));
if (m.originalName!= null) {
<CHANGEE>
<CHANGES>
out.append(escapeString(m.originalName));
<CHANGEE>
<CHANGES>
out.append("]\n");
<CHANGEE>
<CHANGES>
void appendMappings(Appendable out) throws IOException {
for (Mapping m : mappings) {
if (m.used) {
appendMappingTo(m, out);
}
}
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
mapping.sourceFile = sourceFile;
<CHANGEE>
<CHANGES>
mapping.originalName = originalName;
<CHANGEE>
<CHANGES>
if (offsetPosition.getLineNumber() == 0
&& offsetPosition.getCharacterIndex() == 0) {
mapping.startPosition = startPosition;
mapping.endPosition = endPosition;
} else {
<CHANGEE>
<CHANGES>
}
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
int maxLine = prepMappings();
<CHANGEE>
<CHANGES>
(new MappingWriter()).appendMappings(out);
<CHANGEE>
<CHANGES>
private int prepMappings() throws IOException {
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(new UsedMappingCheck());
<CHANGEE>
<CHANGES>
int id = 0;
int maxLine = 0;
for (Mapping m : mappings) {
if (m.used) {
m.id = id++;
int endPositionLine = m.endPosition.getLineNumber();
maxLine = Math.max(maxLine, endPositionLine);
}
}
<CHANGEE>
<CHANGES>
return maxLine + prefixPosition.getLineNumber();
}
private class LineMapper implements MappingVisitor {
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private int lastId = UNMAPPED;
private String lastIdString = UNMAPPED_STRING;
<CHANGEE>
<CHANGES>
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
int id = (m!= null)? m.id : UNMAPPED;
if (lastId!= id) {
<CHANGEE>
<CHANGES>
lastIdString = (id == UNMAPPED)? UNMAPPED_STRING : String.valueOf(id);
lastId = id;
}
String idString = lastIdString;
for (int i = line; i <= nextLine; i++) {
if (i == nextLine) {
for (int j = col; j < nextCol; j++) {
addCharEntry(idString);
}
break;
}
closeLine();
openLine();
}
}
<CHANGEE>
<CHANGES>
(new MappingTraversal()).traverse(this);
<CHANGEE>
<CHANGES>
closeLine();
}
<CHANGEE>
<CHANGES>
private void openLine() throws IOException {
if (out!= null) {
out.append("[");
this.firstChar = true;
}
}
<CHANGEE>
<CHANGES>
private void closeLine() throws IOException {
if (out!= null) {
out.append("]\n");
}
}
<CHANGEE>
<CHANGES>
private void addCharEntry(String id) throws IOException {
if (out!= null) {
if (firstChar) {
firstChar = false;
} else {
out.append(",");
}
out.append(id);
}
}
}
<CHANGEE>
<CHANGES>
private class UsedMappingCheck implements MappingVisitor {
<CHANGEE>
<CHANGES>
@Override
public void visit(Mapping m, int line, int col, int nextLine, int nextCol)
throws IOException {
if (m!= null) {
m.used = true;
}
}
}
private interface MappingVisitor {
<CHANGEE>
<CHANGES>
void visit(Mapping m, int line, int col, int endLine, int endCol)
throws IOException;
}
<CHANGEE>
<CHANGES>
private class MappingTraversal {
<CHANGEE>
<CHANGES>
private int line;
private int col;
MappingTraversal() {
}
<CHANGEE>
<CHANGES>
void traverse(MappingVisitor v) throws IOException {
Preconditions.checkState(!mappings.isEmpty());
<CHANGEE>
<CHANGES>
maybeVisit(v, previous);
<CHANGEE>
<CHANGES>
maybeVisitParent(v, parent, m);
<CHANGEE>
<CHANGES>
maybeVisit(v, m);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
private void maybeVisit(MappingVisitor v, Mapping m) throws IOException {
<CHANGEE>
<CHANGES>
visit(v, m, nextLine, nextCol);
<CHANGEE>
<CHANGES>
private void maybeVisitParent(MappingVisitor v, Mapping parent, Mapping m)
<CHANGEE>
<CHANGES>
int nextLine = getAdjustedLine(m.startPosition);
int nextCol = getAdjustedCol(m.startPosition);
<CHANGEE>
<CHANGES>
Preconditions.checkState(line < nextLine || col <= nextCol);
if (line < nextLine || (line == nextLine && col < nextCol)) {
visit(v, parent, nextLine, nextCol);
}
<CHANGEE>
<CHANGES>
private void visit(MappingVisitor v, Mapping m,
int nextLine, int nextCol)
<CHANGEE>
<CHANGES>
Preconditions.checkState(line <= nextLine);
Preconditions.checkState(line < nextLine || col < nextCol);
<CHANGEE>
<CHANGES>
Preconditions.checkState(false);
<CHANGEE>
<CHANGES>
v.visit(m, line, col, nextLine, nextCol);
<CHANGEE>
<FILEE>
<FILEB>
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
<CHANGES>
<CHANGEE>
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
<FILEE>
<FILEB>
import com.google.common.collect.Lists;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
/**
* Collects information mapping the generated (compiled) source back to
* its original source for debugging purposes.
*
* @see CodeConsumer
* @see CodeGenerator
* @see CodePrinter
*
*
* @author johnlenz@google.com (John Lenz)
*/
public class SourceMap {
<CHANGES>
<CHANGEE>
/**
* A mapping from a given position in an input source file to a given position
* in the generated code.
*/
static class Mapping {
/**
* A unique ID for this mapping for record keeping purposes.
*/
<CHANGES>
int id;
<CHANGEE>
/**
* The input source file.
*/
String sourceFile;
/**
* The position of the code in the input source file. Both
* the line number and the character index are indexed by
* 1 for legacy reasons via the Rhino Node class.
*/
Position originalPosition;
/**
* The starting position of the code in the generated source
* file which this mapping represents. Indexed by 0.
*/
Position startPosition;
/**
* The<SCANS> (subTypes != null) {
for (int i = 0; i < subTypes.size(); i++) {
subTypes.set(i, (FunctionType) subTypes.get(i).resolve(t, scope));
}
}
return super.resolveInternal(t, scope);
}
@Override
public String toDebugHashCodeString() {
if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) {
return super.toDebugHashCodeString();
}
StringBuilder b = new StringBuilder(32);
b.append("function (");
int paramNum = call.parameters.getChildCount();
boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType();
if (hasKnownTypeOfThis) {
b.append("this:");
b.append(getDebugHashCodeStringOf(typeOfThis));
}
if (paramNum > 0) {
if (hasKnownTypeOfThis) {
b.append(", ");
}
Node p = call.parameters.getFirstChild();
b.append(getDebugHashCodeStringOf(p.getJSType()));
p = p.getNext();
while (p != null) {
b.append(", ");
b.append(getDebugHashCodeStringOf(p.getJSType()));
p = p.getNext();
}
}
b.append(")");
b.append(": ");
b.append(getDebugHashCodeStringOf(call.returnType));
return b.toString();
}
private String getDebugHashCodeStringOf(JSType type) {
if (type == this) {
return "me";
} else {
return type.toDebugHashCodeString();
}
}
}